options) {
217 | this.options = Optional.ofNullable(options);
218 | return this;
219 | }
220 |
221 | @Override
222 | public String toString() {
223 | return Objects.toStringHelper(this)
224 | .add("browserType", browserType)
225 | .add("baseTestUrl", baseTestUrl)
226 | .add("webDriverPath", webDriverPath)
227 | .add("browserBinaryPath", browserBinaryPath)
228 | .add("browserLocale", browserLocale)
229 | .add("startWindowWidth", startWindowWidth)
230 | .add("startWindowHeight", startWindowHeight)
231 | .add("browserLogLevel", browserLogLevel)
232 | .add("browserLogFile", browserLogFile)
233 | .add("options", options)
234 | .toString();
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/MobileBrowserBuilder.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser;
2 |
3 | import com.google.common.base.Objects;
4 | import com.google.common.base.Preconditions;
5 | import com.jivesoftware.selenium.pagefactory.framework.browser.mobile.AndroidMobileBrowser;
6 | import com.jivesoftware.selenium.pagefactory.framework.browser.mobile.IOSMobileBrowser;
7 | import com.jivesoftware.selenium.pagefactory.framework.browser.mobile.MobileBrowser;
8 | import com.jivesoftware.selenium.pagefactory.framework.browser.mobile.MobilePlatformName;
9 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig;
10 | import com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | /**
15 | * Created By amir.simhi on 8/20/14.
16 | *
17 | * Builder class for creating an App that is running on an emulator or a connected device that connected
18 | * to the same host as the test code.
19 | * Creates either a {@link com.jivesoftware.selenium.pagefactory.framework.browser.mobile.AndroidMobileBrowser},
20 | * {@link com.jivesoftware.selenium.pagefactory.framework.browser.mobile.IOSMobileBrowser}..
21 | *
22 | * A Browser is basically a wrapper for a WebDriver that greatly simplifies configuration,
23 | * adds useful utilities, and has methods
24 | * for loading {@link com.jivesoftware.selenium.pagefactory.framework.pages.Page}'s.
25 | *
26 | * Pages provide an object-oriented solution to Selenium testing. You can write Page classes that model a web page
27 | * in the web app you are testing.
28 | */
29 | public class MobileBrowserBuilder {
30 | private static final Logger logger = LoggerFactory.getLogger(MobileBrowserBuilder.class);
31 |
32 | private String baseTestUrl;
33 | private TimeoutsConfig timeoutsConfig;
34 | private String browserName;
35 | private MobilePlatformName platformName;
36 | private String platformVersion;
37 | private String platform;
38 | private String deviceName;
39 | private String app;
40 | private String appPackage;
41 | private String appActivity;
42 | private String newCommandTimeout;
43 | private String automationName;
44 | private String version;
45 | private String autoLaunch;
46 | private boolean fullReset;
47 | private boolean touchMode;
48 |
49 |
50 | private MobileBrowserBuilder(String baseTestUrl,
51 | MobilePlatformName platformName) {
52 | this.baseTestUrl = Preconditions.checkNotNull(baseTestUrl, "You must provide a non-null baseTestUrl!");
53 | this.timeoutsConfig = TimeoutsConfig.defaultTimeoutsConfig();
54 | this.platformName = Preconditions.checkNotNull(platformName, "You must provide a non-null platformName!");
55 | this.fullReset = true;
56 |
57 | }
58 |
59 | //------------Getters in case the client wants to inspect the config they have so far-----------
60 | public String getBaseTestUrl() {
61 | return baseTestUrl;
62 | }
63 |
64 | public TimeoutsConfig getTimeoutsConfig() {
65 | return timeoutsConfig;
66 | }
67 |
68 | public String getBrowserName() {
69 | return browserName;
70 | }
71 |
72 | public MobilePlatformName getPlatformName() {
73 | return platformName;
74 | }
75 |
76 | public String getPlatformVersion() {
77 | return platformVersion;
78 | }
79 |
80 | public String getPlatform() {
81 | return platform;
82 | }
83 |
84 | public String getNewCommandTimeout() {
85 | return newCommandTimeout;
86 | }
87 |
88 | public String getAutomationName() {
89 | return automationName;
90 | }
91 |
92 | public String getVersion() {
93 | return version;
94 | }
95 |
96 | public String getAutoLaunch() {
97 | return autoLaunch;
98 | }
99 |
100 | public String getDeviceName() {
101 | return deviceName;
102 | }
103 |
104 | public String getApp() {
105 | return app;
106 | }
107 |
108 | public String getAppPackage() {
109 | return appPackage;
110 | }
111 |
112 | public String getAppActivity() {
113 | return appActivity;
114 | }
115 |
116 | public boolean isTouchMode() {
117 | return touchMode;
118 | }
119 |
120 | public boolean isFullReset() {
121 | return fullReset;
122 | }
123 |
124 | /**
125 | * Get a MobileBrowserBuilder for Android and base URL for the webapp you are testing against.
126 | * @param baseTestUrl - base URL for your webapp, e.g. http://my.site.com/base
127 | */
128 | public static MobileBrowserBuilder getAndroidBuilder(String baseTestUrl) {
129 | return new MobileBrowserBuilder(baseTestUrl, MobilePlatformName.ANDROID);
130 | }
131 |
132 | /**
133 | * Get a MobileBrowserBuilder for iOS and base URL for the webapp you are testing against.
134 | * @param baseTestUrl - base URL for your webapp, e.g. http://my.site.com/base
135 | */
136 | public static MobileBrowserBuilder getIOSBuilder(String baseTestUrl) {
137 | return new MobileBrowserBuilder(baseTestUrl, MobilePlatformName.IOS);
138 | }
139 |
140 |
141 | /**
142 | * Creates the MobileBrowser instance, which includes creating the actual Browser process via the underlying Appium
143 | * Server
144 | * @return - a {@link com.jivesoftware.selenium.pagefactory.framework.browser.mobile.AndroidMobileBrowser},
145 | * {@link com.jivesoftware.selenium.pagefactory.framework.browser.mobile.IOSMobileBrowser}
146 | * @throws com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException when something goes wrong with creating a new WebDriver
147 | */
148 | public MobileBrowser build() throws JiveWebDriverException {
149 | logger.info("Building Mobile Browser with the following config: \n{}", toString());
150 | MobileBrowser browser;
151 | switch (platformName) {
152 | case ANDROID:
153 | browser = new AndroidMobileBrowser(baseTestUrl, browserName, platform, platformName.getPlatformName(),
154 | platformVersion, deviceName, newCommandTimeout, automationName, version, autoLaunch,
155 | app, appPackage, appActivity, timeoutsConfig, touchMode, fullReset);
156 | break;
157 | case IOS:
158 | browser = new IOSMobileBrowser(baseTestUrl, browserName, platform, platformName.getPlatformName(),
159 | platformVersion, deviceName, newCommandTimeout, automationName, version, autoLaunch,
160 | app, fullReset, timeoutsConfig);
161 | break;
162 | default:
163 | throw new IllegalArgumentException("Only IOS and Android are currently supported!");
164 | }
165 | browser.initializeBrowser();
166 | return browser;
167 | }
168 |
169 | public MobileBrowserBuilder withTouchMode(boolean touchMode) {
170 | this.touchMode = touchMode;
171 | return this;
172 | }
173 |
174 | public MobileBrowserBuilder withTimeoutsConfig(TimeoutsConfig timeoutsConfig) {
175 | this.timeoutsConfig = timeoutsConfig == null ? TimeoutsConfig.defaultTimeoutsConfig() : timeoutsConfig;
176 | return this;
177 | }
178 |
179 | public MobileBrowserBuilder withBrowserName(String browserName) {
180 | this.browserName = browserName;
181 | return this;
182 | }
183 |
184 | public MobileBrowserBuilder withPlatformName(MobilePlatformName platformName) {
185 | this.platformName = platformName;
186 | return this;
187 | }
188 |
189 | public MobileBrowserBuilder withPlatformVersion(String platformVersion) {
190 | this.platformVersion = platformVersion;
191 | return this;
192 | }
193 |
194 | public MobileBrowserBuilder withDeviceName(String deviceName) {
195 | this.deviceName = deviceName;
196 | return this;
197 | }
198 |
199 | public MobileBrowserBuilder withApp(String app) {
200 | this.app = app;
201 | return this;
202 | }
203 |
204 | public MobileBrowserBuilder withAppPackage(String appPackage) {
205 | this.appPackage = appPackage;
206 | return this;
207 | }
208 |
209 | public MobileBrowserBuilder withAppActivity(String appActivity) {
210 | this.appActivity = appActivity;
211 | return this;
212 | }
213 |
214 | public MobileBrowserBuilder withNewCommandTimeout(String newCommandTimeout) {
215 | this.newCommandTimeout = newCommandTimeout;
216 | return this;
217 | }
218 |
219 | public MobileBrowserBuilder withAutomationName(String automationName) {
220 | this.automationName = automationName;
221 | return this;
222 | }
223 |
224 | public MobileBrowserBuilder withVersion(String version) {
225 | this.version = version;
226 | return this;
227 | }
228 |
229 | public MobileBrowserBuilder withAutoLaunch(String autoLaunch) {
230 | this.autoLaunch = autoLaunch;
231 | return this;
232 | }
233 |
234 | public MobileBrowserBuilder withPlatform(String platform) {
235 | this.platform = platform;
236 | return this;
237 | }
238 |
239 | public MobileBrowserBuilder withFullReset(boolean fullReset) {
240 | this.fullReset = fullReset;
241 | return this;
242 | }
243 |
244 | @Override
245 | public String toString() {
246 | return Objects.toStringHelper(this)
247 | .add("baseTestUrl", baseTestUrl)
248 | .add("browserName", browserName)
249 | .add("platformName", platformName.getPlatformName())
250 | .add("platform", platform)
251 | .add("platformVersion", platformVersion)
252 | .add("deviceName", deviceName)
253 | .add("app", app)
254 | .add("appPackage", appPackage)
255 | .add("appActivity", appActivity)
256 | .add("newCommandTimeout", newCommandTimeout)
257 | .add("automationName", automationName)
258 | .add("version", version)
259 | .add("autoLaunch", autoLaunch)
260 | .toString();
261 | }
262 | }
263 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/RemoteBrowserBuilder.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser;
2 |
3 | import com.google.common.base.Objects;
4 | import com.google.common.base.Preconditions;
5 | import com.jivesoftware.selenium.pagefactory.framework.browser.web.ChromeBrowser;
6 | import com.jivesoftware.selenium.pagefactory.framework.browser.web.FirefoxBrowser;
7 | import com.jivesoftware.selenium.pagefactory.framework.browser.web.InternetExplorerBrowser;
8 | import com.jivesoftware.selenium.pagefactory.framework.browser.web.RemoteBrowser;
9 | import com.jivesoftware.selenium.pagefactory.framework.browser.web.SafariBrowser;
10 | import com.jivesoftware.selenium.pagefactory.framework.browser.web.WebBrowser;
11 | import com.jivesoftware.selenium.pagefactory.framework.browser.web.WebBrowserType;
12 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig;
13 | import com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException;
14 | import org.openqa.selenium.Platform;
15 | import org.slf4j.Logger;
16 | import org.slf4j.LoggerFactory;
17 |
18 | import java.util.List;
19 | import java.util.Optional;
20 | import java.util.logging.Level;
21 |
22 | /**
23 | * Created by charles.capps on 8/18/14.
24 | *
25 | * Builder class for creating a {@link com.jivesoftware.selenium.pagefactory.framework.browser.web.RemoteBrowser}.
26 | * A RemoteBrowser is a browser running in a Selenium Grid, that works
27 | * by connecting to a Selenium Hub. See https://code.google.com/p/selenium/wiki/Grid2
28 | *
29 | * In other words, a RemoteBrowser is a wrapper around a {@link org.openqa.selenium.remote.RemoteWebDriver}
30 | * that simplifies configuration and unifies options across all Browsers.
31 | *
32 | * You can call {@link #getBuilder(WebBrowserType, String, String)} to get a builder, or you can equivalently call
33 | * {@link #getChromeBuilder(String, String)}, {@link #getFirefoxBuilder(String, String)}, or {@link #getInternetExplorerBuilder(String, String)}.
34 | *
35 | * Calling RemoteBrowserBuilder.getBuilder(BrowserType.CHROME, ...)
36 | * is equivalent to calling RemoteBrowserBuilder.getChromeBuilder(...).
37 | */
38 | public class RemoteBrowserBuilder {
39 | private static final Logger logger = LoggerFactory.getLogger(RemoteBrowserBuilder.class);
40 |
41 | private final WebBrowserType browserType;
42 | private final String baseTestUrl;
43 | private final String seleniumHubURL;
44 |
45 | private TimeoutsConfig timeoutsConfig;
46 |
47 | private Optional browserVersion = Optional.empty();
48 | private Optional browserLocale = Optional.empty();
49 | private Optional startWindowWidth = Optional.empty();
50 | private Optional startWindowHeight = Optional.empty();
51 | private Optional browserLogLevel = Optional.empty();
52 | private Optional browserLogFile = Optional.empty();
53 | private Optional platform = Optional.empty();
54 | private Optional> options = Optional.empty();
55 |
56 | private RemoteBrowserBuilder(WebBrowserType browserType,
57 | String baseTestUrl,
58 | String seleniumHubURL) {
59 | this.browserType = Preconditions.checkNotNull(browserType, "You must provide a non-null BrowserType!");
60 | this.baseTestUrl = Preconditions.checkNotNull(baseTestUrl, "You must provide a non-null baseTestUrl!");
61 | this.seleniumHubURL = Preconditions.checkNotNull(seleniumHubURL, "You must provide a non-null seleniumHubURL");
62 | this.timeoutsConfig = TimeoutsConfig.defaultTimeoutsConfig();
63 | }
64 |
65 | //------------Getters in case the client wants to inspect the config they have so far-----------
66 | public WebBrowserType getBrowserType() {
67 | return browserType;
68 | }
69 |
70 | public String getBaseTestUrl() {
71 | return baseTestUrl;
72 | }
73 |
74 | public String getSeleniumHubURL() {
75 | return seleniumHubURL;
76 | }
77 |
78 | public TimeoutsConfig getTimeoutsConfig() {
79 | return timeoutsConfig;
80 | }
81 |
82 | public Optional getBrowserVersion() {
83 | return browserVersion;
84 | }
85 |
86 | public Optional getBrowserLocale() {
87 | return browserLocale;
88 | }
89 |
90 | public Optional getStartWindowWidth() {
91 | return startWindowWidth;
92 | }
93 |
94 | public Optional getStartWindowHeight() {
95 | return startWindowHeight;
96 | }
97 |
98 | public Optional getBrowserLogLevel() {
99 | return browserLogLevel;
100 | }
101 |
102 | public Optional getBrowserLogFile() {
103 | return browserLogFile;
104 | }
105 |
106 | public Optional getPlatform() {
107 | return platform;
108 | }
109 |
110 | public Optional> getOptions() {
111 | return options;
112 | }
113 |
114 |
115 | /**
116 | * Get a RemoteBrowserBuilder used to construct a RemoteBrowser instance that helps you to run Selenium tests
117 | * against a remote Browser running in a Selenium Grid.
118 | *
119 | * @param browserType - CHROME, FIREFOX, or IE
120 | * @param baseTestUrl - base URL of the webapp you are testing, e.g. http://my.site.com/base
121 | * @param seleniumHubURL - URL with port to the Selenium HUB, e.g. http://selenium.my.company.com:4444/wd/hub
122 | */
123 | public static RemoteBrowserBuilder getBuilder(WebBrowserType browserType,
124 | String baseTestUrl,
125 | String seleniumHubURL) {
126 | return new RemoteBrowserBuilder(browserType, baseTestUrl, seleniumHubURL);
127 | }
128 |
129 | /**
130 | * Get a RemoteBrowserBuilder used to construct a RemoteBrowser instance that helps you to run Selenium tests
131 | * against a remote Browser running in a Selenium Grid. For CHROME browser.
132 | *
133 | * @param baseTestUrl - base URL of the webapp you are testing, e.g. http://my.site.com/base
134 | * @param seleniumHubURL - URL with port to the Selenium HUB, e.g. http://selenium.my.company.com:4444/wd/hub
135 | */
136 | public static RemoteBrowserBuilder getChromeBuilder(String baseTestUrl, String seleniumHubURL) {
137 | return new RemoteBrowserBuilder(WebBrowserType.CHROME, baseTestUrl, seleniumHubURL);
138 | }
139 |
140 | /**
141 | * Get a RemoteBrowserBuilder used to construct a RemoteBrowser instance that helps you to run Selenium tests
142 | * against a remote Browser running in a Selenium Grid. For FIREFOX browser.
143 | *
144 | * @param baseTestUrl - base URL of the webapp you are testing, e.g. http://my.site.com/base
145 | * @param seleniumHubURL - URL with port to the Selenium HUB, e.g. http://selenium.my.company.com:4444/wd/hub
146 | */
147 | public static RemoteBrowserBuilder getFirefoxBuilder(String baseTestUrl, String seleniumHubURL) {
148 | return new RemoteBrowserBuilder(WebBrowserType.FIREFOX, baseTestUrl, seleniumHubURL);
149 | }
150 |
151 | /**
152 | * Get a RemoteBrowserBuilder used to construct a RemoteBrowser instance that helps you to run Selenium tests
153 | * against a remote Browser running in a Selenium Grid. For IE browser.
154 | *
155 | * @param baseTestUrl - base URL of the webapp you are testing, e.g. http://my.site.com/base
156 | * @param seleniumHubURL - URL with port to the Selenium HUB, e.g. http://selenium.my.company.com:4444/wd/hub
157 | */
158 | public static RemoteBrowserBuilder getInternetExplorerBuilder(String baseTestUrl, String seleniumHubURL) {
159 | return new RemoteBrowserBuilder(WebBrowserType.IE, baseTestUrl, seleniumHubURL);
160 | }
161 |
162 | /**
163 | * Creates the RemoteBrowser instance, which includes creating the actual Browser process via the underlying WebDriver.
164 | *
165 | * @return - a {@link com.jivesoftware.selenium.pagefactory.framework.browser.web.RemoteBrowser},
166 | * @throws JiveWebDriverException when something goes wrong with creating a new WebDriver.
167 | */
168 | public RemoteBrowser build() throws JiveWebDriverException {
169 | logger.info("Building Remote Browser with the following config: \n{}", toString());
170 | WebBrowser browser;
171 | switch (browserType) {
172 | case FIREFOX:
173 | browser = new FirefoxBrowser(baseTestUrl, timeoutsConfig, Optional.empty(), Optional.empty(), browserVersion, browserLocale, startWindowWidth, startWindowHeight, platform);
174 | break;
175 | case CHROME:
176 | browser = new ChromeBrowser(baseTestUrl, timeoutsConfig, Optional.empty(), Optional.empty(), browserVersion, browserLocale, startWindowWidth, startWindowHeight,
177 | browserLogLevel, browserLogFile, platform, options);
178 | break;
179 | case IE:
180 | browser = new InternetExplorerBrowser(baseTestUrl, timeoutsConfig, Optional.empty(), Optional.empty(), browserVersion, browserLocale, startWindowWidth, startWindowHeight,
181 | browserLogLevel, browserLogFile, platform);
182 | break;
183 | case SAFARI:
184 | browser = new SafariBrowser(baseTestUrl, timeoutsConfig, Optional.empty(), Optional.empty(), browserVersion, browserLocale, startWindowWidth, startWindowHeight,
185 | browserLogLevel, browserLogFile, Optional.empty());
186 | break;
187 | default:
188 | throw new IllegalArgumentException("Only FIREFOX, CHROME, IE, and SAFARI are currently supported!");
189 | }
190 | RemoteBrowser remoteBrowser = new RemoteBrowser(browser, seleniumHubURL);
191 | remoteBrowser.initializeBrowser();
192 | return remoteBrowser;
193 | }
194 |
195 | public RemoteBrowserBuilder withTimeoutsConfig(TimeoutsConfig timeoutsConfig) {
196 | this.timeoutsConfig = timeoutsConfig == null ? TimeoutsConfig.defaultTimeoutsConfig() : timeoutsConfig;
197 | return this;
198 | }
199 |
200 | public RemoteBrowserBuilder withBrowserVersion(String browserVersion) {
201 | this.browserVersion = Optional.ofNullable(browserVersion);
202 | return this;
203 | }
204 |
205 | public RemoteBrowserBuilder withBrowserLocale(String browserLocale) {
206 | this.browserLocale = Optional.ofNullable(browserLocale);
207 | return this;
208 | }
209 |
210 | public RemoteBrowserBuilder withStartWindowWidth(Integer startWindowWidth) {
211 | this.startWindowWidth = Optional.ofNullable(startWindowWidth);
212 | return this;
213 | }
214 |
215 | public RemoteBrowserBuilder withStartWindowHeight(Integer startWindowHeight) {
216 | this.startWindowHeight = Optional.ofNullable(startWindowHeight);
217 | return this;
218 | }
219 |
220 | public RemoteBrowserBuilder withBrowserLogLevel(Level browserLogLevel) {
221 | this.browserLogLevel = Optional.ofNullable(browserLogLevel);
222 | return this;
223 | }
224 |
225 | public RemoteBrowserBuilder withBrowserLogFile(String browserLogFile) {
226 | this.browserLogFile = Optional.ofNullable(browserLogFile);
227 | return this;
228 | }
229 |
230 | public RemoteBrowserBuilder withPlatform(Platform platform) {
231 | this.platform = Optional.ofNullable(platform);
232 | return this;
233 | }
234 |
235 | public RemoteBrowserBuilder withOptions(List options) {
236 | this.options = Optional.ofNullable(options);
237 | return this;
238 | }
239 |
240 | @Override
241 | public String toString() {
242 | return Objects.toStringHelper(this)
243 | .add("browserType", browserType)
244 | .add("baseTestUrl", baseTestUrl)
245 | .add("seleniumHubURL", seleniumHubURL)
246 | .add("browserVersion", browserVersion)
247 | .add("browserLocale", browserLocale)
248 | .add("startWindowWidth", startWindowWidth)
249 | .add("startWindowHeight", startWindowHeight)
250 | .add("browserLogLevel", browserLogLevel)
251 | .add("browserLogFile", browserLogFile)
252 | .add("platform", platform)
253 | .add("options", options)
254 | .toString();
255 | }
256 |
257 | }
258 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/mobile/AndroidMobileBrowser.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.mobile;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.actions.AndroidSeleniumActions;
4 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig;
5 | import com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException;
6 | import io.appium.java_client.android.AndroidDriver;
7 | import io.appium.java_client.android.AndroidKeyCode;
8 | import org.openqa.selenium.WebElement;
9 | import org.openqa.selenium.interactions.touch.TouchActions;
10 | import org.openqa.selenium.remote.CapabilityType;
11 | import org.openqa.selenium.remote.DesiredCapabilities;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 |
15 | import java.io.IOException;
16 | import java.net.URL;
17 |
18 | public class AndroidMobileBrowser extends MobileBrowser {
19 |
20 | protected boolean touchMode;
21 | private String appPackage;
22 | private String appActivity;
23 | private static final Logger logger = LoggerFactory.getLogger(AndroidMobileBrowser.class);
24 |
25 | public AndroidMobileBrowser(String baseTestUrl,
26 | String browserName,
27 | String platform,
28 | String platformName,
29 | String platformVersion,
30 | String deviceName,
31 | String newCommandTimeout,
32 | String automationName,
33 | String version,
34 | String autoLaunch,
35 | String app,
36 | String appPackage,
37 | String appActivity,
38 | TimeoutsConfig timeouts,
39 | boolean touchMode,
40 | boolean fullReset) throws JiveWebDriverException {
41 | super(baseTestUrl, timeouts, browserName, platform, platformName, platformVersion, deviceName,
42 | newCommandTimeout, automationName, version, autoLaunch, app, fullReset);
43 | this.touchMode = touchMode;
44 | this.appPackage = appPackage;
45 | this.appActivity = appActivity;
46 | }
47 |
48 | @Override
49 | public DesiredCapabilities getDesiredCapabilities() {
50 | DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
51 | desiredCapabilities.setCapability(CapabilityType.BROWSER_NAME, browserName);
52 | desiredCapabilities.setCapability("platform", platform);
53 | desiredCapabilities.setCapability("platformName", platformName);
54 | desiredCapabilities.setCapability("platformVersion", platformVersion);
55 | desiredCapabilities.setCapability("deviceName", deviceName);
56 | desiredCapabilities.setCapability("newCommandTimeout", newCommandTimeout);
57 | desiredCapabilities.setCapability("automationName", automationName);
58 | desiredCapabilities.setCapability("version", version);
59 | desiredCapabilities.setCapability("autoLaunch", autoLaunch);
60 | desiredCapabilities.setCapability("app", app);
61 | desiredCapabilities.setCapability("appPackage", appPackage);
62 | desiredCapabilities.setCapability("appWaitActivity", appActivity);
63 | desiredCapabilities.setCapability("fullReset", fullReset);
64 | desiredCapabilities.setCapability(CapabilityType.ForSeleniumServer.ENSURING_CLEAN_SESSION, true);
65 | return desiredCapabilities;
66 | }
67 |
68 | protected AndroidDriver createWebDriver() throws JiveWebDriverException {
69 | try {
70 | printCapabilities(getDesiredCapabilities());
71 | return new SwipeableWebDriver(new URL(getBaseTestUrl()), getDesiredCapabilities());
72 | } catch (IOException e) {
73 | throw new JiveWebDriverException("Error starting appium driver service", e);
74 | }
75 | }
76 |
77 | @Override
78 | public AndroidSeleniumActions getActions() {
79 | return new AndroidSeleniumActions(this);
80 | }
81 |
82 | public String getAppPackage() {
83 | return appPackage;
84 | }
85 |
86 | public String getAppActivity() {
87 | return appActivity;
88 | }
89 |
90 | /**
91 | *
92 | * @return true if Android is API 17 or down, and as a result uses touch mode
93 | */
94 | public boolean isTouchMode() {
95 | return touchMode;
96 | }
97 |
98 | /**
99 | *
100 | * @param touchMode - true if Android is API 17 or lower
101 | */
102 | public void setTouchMode(boolean touchMode) {
103 | this.touchMode = touchMode;
104 | }
105 |
106 | /**
107 | * Swipe from the top to bottom for a second
108 | */
109 | @Override
110 | public void dragDown() {
111 | int midScreen = getScreenWidth() / 2;
112 | if (touchMode) {
113 | TouchActions action = new TouchActions(webDriver);
114 | action.down(midScreen, 360).move(midScreen, 300).up(midScreen, 300).perform();
115 | } else {
116 | webDriver.swipe(midScreen, 450, midScreen, getScreenHeight() - 250, 1500);
117 | }
118 | }
119 |
120 | /**
121 | * Swipe from the down to up for a second
122 | */
123 | @Override
124 | public void dragUp() {
125 | int midScreen = webDriver.manage().window().getSize().getWidth() / 2;
126 | if (touchMode) {
127 | TouchActions action = new TouchActions(webDriver);
128 | action.down(midScreen, 300).move(midScreen, 250).up(midScreen, 250).perform();
129 | } else {
130 | webDriver.swipe(midScreen, getScreenHeight() - 250, midScreen, 250, 2500);
131 | }
132 | }
133 |
134 | /**
135 | * Swipe from the top to bottom for a second
136 | *
137 | * @param yStart - coordinate to start swiping
138 | * @param yEnd - coordinate to stop swiping
139 | */
140 | @Override
141 | public void drag(int yStart, int yEnd) {
142 | int midScreen = getScreenWidth() / 2;
143 | if (touchMode) {
144 | TouchActions action = new TouchActions(webDriver);
145 | action.down(midScreen, yStart).move(midScreen, yEnd).up(midScreen, yEnd).perform();
146 | } else {
147 | webDriver.swipe(midScreen, yStart, midScreen, yEnd, 2500);
148 | }
149 | }
150 |
151 | /**
152 | * Swipe from the top to bottom for a second
153 | *
154 | * @param yStart - coordinate to start swiping
155 | * @param yEnd - coordinate to stop swiping
156 | */
157 |
158 | @Override
159 | public void drag(int yStart, int yEnd, int duration) {
160 | int midScreen = getScreenWidth() / 2;
161 | if (touchMode) {
162 | TouchActions action = new TouchActions(webDriver);
163 | action.down(midScreen, yStart).move(midScreen, yEnd).up(midScreen, yEnd).perform();
164 | } else {
165 | webDriver.swipe(midScreen, yStart, midScreen, yEnd, duration);
166 | }
167 | }
168 |
169 | @Override
170 | public void tap(int fingersNum, WebElement webElement, int duration) {
171 | if (touchMode) {
172 | TouchActions action = new TouchActions(webDriver);
173 | try {
174 | action.down(webElement.getLocation().getX(), webElement.getLocation().getY()).clickAndHold()
175 | .release(webElement).perform();
176 | } catch (NullPointerException e) {
177 |
178 | }
179 | } else {
180 | webDriver.tap(fingersNum, webElement, duration);
181 | }
182 | }
183 |
184 | @Override
185 | public void tap(int fingersNum, int xLocation, int yLocation, int duration) {
186 | if (touchMode) {
187 | TouchActions action = new TouchActions(webDriver);
188 | try {
189 | action.down(xLocation, yLocation).clickAndHold().perform();
190 | } catch (NullPointerException e) {
191 | logger.error("Failed To Tap due to NullPointerException", e.getStackTrace());
192 | }
193 | } else {
194 | webDriver.tap(fingersNum, xLocation, yLocation, duration);
195 | }
196 | }
197 |
198 | public void clickHomePage() {
199 | webDriver.sendKeyEvent(AndroidKeyCode.HOME);
200 | }
201 |
202 | public void clickBack() {
203 | webDriver.sendKeyEvent(AndroidKeyCode.BACK);
204 | }
205 |
206 | @Override
207 | public void scrollToTop() {
208 | logger.error("Method ScrollToTop is not yet implemented");
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/mobile/IOSMobileBrowser.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.mobile;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.actions.IOSSeleniumActions;
4 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig;
5 | import com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException;
6 | import io.appium.java_client.ios.IOSDriver;
7 | import org.openqa.selenium.remote.CapabilityType;
8 | import org.openqa.selenium.remote.DesiredCapabilities;
9 |
10 | import java.io.IOException;
11 | import java.net.URL;
12 | import java.util.HashMap;
13 |
14 |
15 | /**
16 | * Added by Shiran.Dadon
17 | * Known bug of Apple from Xcode 5 and iOS 7.1 Simulator - swipe is not working on simulator.
18 | * As a workaround, using scrollTo in JavaScript.
19 | * As in real devices regular swipe works but not scrollTo, using the regular command as well
20 | */
21 |
22 | public class IOSMobileBrowser extends MobileBrowser {
23 |
24 | public IOSMobileBrowser(String baseTestUrl,
25 | String browserName,
26 | String platform,
27 | String platformName,
28 | String platformVersion,
29 | String deviceName,
30 | String newCommandTimeout,
31 | String automationName,
32 | String version,
33 | String autoLaunch,
34 | String app,
35 | boolean fullReset,
36 | TimeoutsConfig timeouts) throws JiveWebDriverException {
37 | super(baseTestUrl, timeouts, browserName, platform, platformName, platformVersion, deviceName,
38 | newCommandTimeout, automationName, version, autoLaunch, app, fullReset);
39 | }
40 |
41 | @Override
42 | public DesiredCapabilities getDesiredCapabilities() {
43 | DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
44 | desiredCapabilities.setCapability(CapabilityType.BROWSER_NAME, browserName);
45 | desiredCapabilities.setCapability("platform", platform);
46 | desiredCapabilities.setCapability("platformName", platformName);
47 | desiredCapabilities.setCapability("platformVersion", platformVersion);
48 | desiredCapabilities.setCapability("deviceName", deviceName);
49 | desiredCapabilities.setCapability("newCommandTimeout", newCommandTimeout);
50 | desiredCapabilities.setCapability("automationName", automationName);
51 | desiredCapabilities.setCapability("version", version);
52 | desiredCapabilities.setCapability("autoLaunch", autoLaunch);
53 | desiredCapabilities.setCapability("app", app);
54 | desiredCapabilities.setCapability("fullReset", fullReset);
55 | desiredCapabilities.setCapability("rotatable", "true");
56 | return desiredCapabilities;
57 | }
58 |
59 | protected IOSDriver createWebDriver() throws JiveWebDriverException {
60 | try {
61 | printCapabilities(getDesiredCapabilities());
62 | return new IOSDriver(new URL(getBaseTestUrl()), getDesiredCapabilities());
63 | } catch (IOException e) {
64 | throw new JiveWebDriverException("Error starting appium driver service", e);
65 | }
66 | }
67 |
68 | @Override
69 | public IOSSeleniumActions getActions() {
70 | return new IOSSeleniumActions(this);
71 | }
72 | /**
73 | * Swipe from the right to left for a second
74 | */
75 | public void swipeLeft() {
76 | super.swipeLeft();
77 | HashMap scrollObject = new HashMap();
78 | scrollObject.put("direction", "left");
79 | webDriver.executeScript("mobile: scroll", scrollObject);
80 | }
81 |
82 | /**
83 | * Swipe from the left to right for a second
84 | */
85 | public void swipeRight() {
86 | super.swipeRight();
87 | HashMap scrollObject = new HashMap();
88 | scrollObject.put("direction", "right");
89 | webDriver.executeScript("mobile: scroll", scrollObject);
90 | }
91 |
92 | /**
93 | * Swipe from the top to buttom for a second
94 | */
95 | public void dragDown() {
96 | int midScreen = getScreenWidth() / 2;
97 | webDriver.swipe(midScreen, 140, midScreen, getScreenHeight() - 140, 1500);
98 | //HashMap scrollObject = new HashMap();
99 | //scrollObject.put("direction", "up");
100 | //webDriver.executeScript("mobile: scroll", scrollObject);
101 | }
102 |
103 | /**
104 | * Swipe from the down to up for a second
105 | */
106 | public void dragUp() {
107 | int midScreen = getScreenWidth() / 2;
108 | webDriver.swipe(midScreen, getScreenHeight() - 140, midScreen, 140, 1500);
109 | // HashMap scrollObject = new HashMap();
110 | //scrollObject.put("direction", "down");
111 | //webDriver.executeScript("mobile: scroll", scrollObject);
112 | }
113 |
114 | /**
115 | * Will function only with real device
116 | * @param startX - 0 is the left side of the smart-phone
117 | * @param endX - coordinate to stop swipe
118 | * @param startY - 0 is the upper side of the smart-phone
119 | * @param endY - coordinate to stop swipe
120 | * @param duration - in milliseconds
121 | */
122 | public void swipe(int startX, int endX, int startY, int endY, int duration) {
123 | webDriver.swipe(startX, startY, endX, endY, duration);
124 | }
125 |
126 | /**
127 | * Uses iOS functionality of automatic scroll to top when clicking status bar
128 | */
129 | public void scrollToTop() {
130 | getWebDriver().findElementByClassName("UIAStatusBar").click();
131 | }
132 |
133 | public void openNotifications() {
134 | int midScreenWidth = getScreenWidth() / 2;
135 | webDriver.swipe(midScreenWidth, 0, midScreenWidth, getScreenHeight(), 1000);
136 | webDriver.quit();
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/mobile/MobileBrowser.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.mobile;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.browser.Browser;
4 | import com.jivesoftware.selenium.pagefactory.framework.browser.web.WebBrowserType;
5 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig;
6 | import com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException;
7 | import com.jivesoftware.selenium.pagefactory.framework.pages.BaseTopLevelPage;
8 | import com.jivesoftware.selenium.pagefactory.framework.pages.TopLevelPage;
9 | import io.appium.java_client.AppiumDriver;
10 | import org.openqa.selenium.ScreenOrientation;
11 | import org.openqa.selenium.WebElement;
12 | import org.openqa.selenium.remote.DesiredCapabilities;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 |
16 | import java.util.Map;
17 | import java.util.concurrent.TimeUnit;
18 |
19 |
20 | /**
21 | * Mobile Browser - Extends Selenium's Appium Driver functionality
22 | * Working on Android and iOS
23 | * Supports pages
24 | */
25 | public abstract class MobileBrowser extends Browser {
26 | private static Logger logger = LoggerFactory.getLogger(MobileBrowser.class);
27 |
28 | protected String browserName;
29 | protected String platform;
30 | protected String platformName;
31 | protected String platformVersion;
32 | protected String deviceName;
33 | protected String newCommandTimeout;
34 | protected String automationName;
35 | protected String version;
36 | protected String autoLaunch;
37 | protected String app;
38 | protected boolean fullReset;
39 |
40 | protected MobileBrowser(String baseTestUrl,
41 | TimeoutsConfig timeoutsConfig, String browserName,
42 | String platform,
43 | String platformName,
44 | String platformVersion,
45 | String deviceName,
46 | String newCommandTimeout,
47 | String automationName,
48 | String version,
49 | String autoLaunch,
50 | String app,
51 | boolean fullReset) throws JiveWebDriverException {
52 | super(baseTestUrl, timeoutsConfig);
53 | this.browserName = browserName;
54 | this.platform = platform;
55 | this.platformName = platformName;
56 | this.platformVersion = platformVersion;
57 | this.deviceName = deviceName;
58 | this.newCommandTimeout = newCommandTimeout;
59 | this.automationName = automationName;
60 | this.version = version;
61 | this.autoLaunch = autoLaunch;
62 | this.app = app;
63 | this.fullReset = fullReset;
64 | }
65 |
66 | public void initializeBrowser() throws JiveWebDriverException {
67 | this.webDriver = createWebDriver();
68 | this.webDriver.manage().timeouts().implicitlyWait(getImplicitWaitTimeoutMillis(), TimeUnit.MILLISECONDS);
69 | }
70 |
71 | public int getScreenWidth() {
72 | return this.webDriver.manage().window().getSize().getWidth();
73 | }
74 |
75 | public int getScreenHeight() {
76 | return this.webDriver.manage().window().getSize().getHeight();
77 | }
78 |
79 | protected abstract AppiumDriver createWebDriver() throws JiveWebDriverException;
80 |
81 | protected void printCapabilities(DesiredCapabilities desiredCapabilities) {
82 | logger.info("Loading capabilities..");
83 | for (Map.Entry desiredCapability : desiredCapabilities.asMap().entrySet()) {
84 | logger.info(desiredCapability.getKey() + " - " + desiredCapability.getValue());
85 | }
86 | }
87 |
88 | /**
89 | * Refresh the current page, without giving back a newly initialized Page object.
90 | */
91 | @Override
92 | public void refreshPage() {
93 | runLeavePageHook();
94 | BaseTopLevelPage currentPage = PAGE_UTILS.loadCurrentPage(BaseTopLevelPage.class, webDriver, this.getActions());
95 | currentPage.refreshPage();
96 | if (optionalCachedPage.isPresent()) {
97 | TopLevelPage cachedPage = optionalCachedPage.get().getCachedPage();
98 | cachedPage.refreshElements();
99 | }
100 | }
101 |
102 | /**
103 | *
104 | * @param pageClass - the class of the expected Page after refreshing.
105 | * @param - class that extends TopLevelPage class
106 | * @return - a page of the requested class
107 | */
108 | @Override
109 | public T refreshPage(Class pageClass) {
110 | runLeavePageHook();
111 | invalidateCachedPage();
112 | T page = loadTopLevelPage(pageClass);
113 | page.refreshPage();
114 | page = loadTopLevelPage(pageClass);
115 | setCachedPage(page);
116 | return page;
117 | }
118 |
119 | @Override
120 | public WebBrowserType getBrowserType() {
121 | return WebBrowserType.MOBILE;
122 | }
123 |
124 | public String getPlatformName() {
125 | return platformName;
126 | }
127 |
128 | public String getPlatform() {
129 | return platform;
130 | }
131 |
132 | public String getPlatformVersion() {
133 | return platformVersion;
134 | }
135 |
136 | public String getDeviceName() {
137 | return deviceName;
138 | }
139 |
140 | public String getApp() {
141 | return app;
142 | }
143 |
144 | //**********~~~~~~~~~~~~~ Mobile Actions ~~~~~~~~~~~~~~~*************
145 |
146 | public void rotateLandscape() {
147 | webDriver.rotate(ScreenOrientation.LANDSCAPE);
148 | }
149 |
150 | public void rotatePortrait() {
151 | webDriver.rotate(ScreenOrientation.PORTRAIT);
152 | }
153 |
154 | /**
155 | * Swipe from the right to left for a second
156 | */
157 | public void swipeLeft() {
158 | webDriver.swipe(getScreenWidth() - 5, getScreenHeight() / 2, 5, getScreenHeight() / 2, 1000);
159 | }
160 |
161 | /**
162 | * Swipe from the left to right for a second
163 | */
164 | public void swipeRight() {
165 | webDriver.swipe(5, getScreenHeight() / 2, getScreenWidth() - 5, getScreenHeight() / 2, 1000);
166 | }
167 |
168 | /**
169 | * Swipe from the top to bottom for a second
170 | */
171 | public void dragDown() {
172 | int midScreen = getScreenWidth() / 2;
173 | webDriver.swipe(midScreen, 250, midScreen, getScreenHeight() - 250, 1500);
174 | }
175 |
176 | /**
177 | * Swipe from the down to up for a second
178 | */
179 | public void dragUp() {
180 | int midScreen = webDriver.manage().window().getSize().getWidth() / 2;
181 | webDriver.swipe(midScreen, getScreenHeight() - 250, midScreen, 250, 2500);
182 | }
183 |
184 | /**
185 | * Swipe from the top to bottom for 2.5 seconds
186 | * @param yStart - 0 is the upper side of the smart-phone
187 | * @param yEnd - the end coordinate of the drag function
188 | */
189 | public void drag(int yStart, int yEnd) {
190 | int midScreen = getScreenWidth() / 2;
191 | webDriver.swipe(midScreen, yStart, midScreen, yEnd, 2500);
192 | }
193 |
194 | public void drag(int yStart, int yEnd, int duration) {
195 | int midScreen = getScreenWidth() / 2;
196 | webDriver.swipe(midScreen, yStart, midScreen, yEnd, duration);
197 | }
198 |
199 | /**
200 | *
201 | * @param startX - 0 is the left side of the smart-phone
202 | * @param endX - end coordinate of the right/left movement
203 | * @param startY - 0 is the upper side of the smart-phone
204 | * @param endY - end coordinate of the up/down movement
205 | * @param duration - in milliseconds
206 | */
207 | public void swipe(int startX, int endX, int startY, int endY, int duration) {
208 | webDriver.swipe(startX, startY, endX, endY, duration);
209 | }
210 |
211 | public void putApplicationToBackground(int duration) {
212 | webDriver.runAppInBackground(duration);
213 | }
214 |
215 | public void lockMobile(int duration) {
216 | webDriver.lockScreen(duration);
217 | }
218 |
219 | public void tap(int fingersNum, WebElement webElement, int duration) {
220 | webDriver.tap(fingersNum, webElement, duration);
221 | }
222 | public void tap(int fingersNum, int xLocation, int yLocation, int duration) {
223 | webDriver.tap(fingersNum, xLocation, yLocation, duration);
224 | }
225 |
226 | public void initApp() {
227 | webDriver.closeApp();
228 | webDriver.launchApp();
229 | }
230 |
231 | public abstract void scrollToTop();
232 | }
233 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/mobile/MobilePlatformName.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.mobile;
2 |
3 | /**
4 | * Created by amir on 8/13/14.
5 | */
6 | public enum MobilePlatformName {
7 | IOS("iOS"),
8 | ANDROID("Android");
9 |
10 | private String platformName;
11 |
12 | private MobilePlatformName(String platformName) {
13 | this.platformName = platformName;
14 | }
15 |
16 | public String getPlatformName() {
17 | return platformName;
18 | }
19 |
20 | public static MobilePlatformName forName(String name) {
21 | for (MobilePlatformName platform : MobilePlatformName.values()) {
22 | if (platform.toString().equalsIgnoreCase(name)) {
23 | return platform;
24 | }
25 | }
26 | throw new IllegalArgumentException("Mobile Platform Name must be 'ANDROID', 'IOS'");
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/mobile/SwipeableWebDriver.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.mobile;
2 |
3 | import io.appium.java_client.MobileElement;
4 | import io.appium.java_client.android.AndroidDriver;
5 | import org.openqa.selenium.Capabilities;
6 | import org.openqa.selenium.interactions.HasTouchScreen;
7 | import org.openqa.selenium.interactions.TouchScreen;
8 | import org.openqa.selenium.remote.RemoteTouchScreen;
9 |
10 | import java.net.URL;
11 |
12 | /**
13 | * Created by amir on 11/18/14.
14 | */
15 | public class SwipeableWebDriver extends AndroidDriver implements HasTouchScreen {
16 | private RemoteTouchScreen touch;
17 |
18 | public SwipeableWebDriver(URL remoteAddress, Capabilities desiredCapabilities) {
19 | super(remoteAddress, desiredCapabilities);
20 | touch = new RemoteTouchScreen(getExecuteMethod());
21 | }
22 |
23 | @Override
24 | public TouchScreen getTouch() {
25 | return touch;
26 | }
27 |
28 | @Override
29 | public MobileElement scrollTo(String s) {
30 | return null;
31 | }
32 |
33 | @Override
34 | public MobileElement scrollToExact(String s) {
35 | return null;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/web/ChromeBrowser.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.web;
2 |
3 | import com.google.common.collect.Maps;
4 | import com.jivesoftware.selenium.pagefactory.framework.actions.ChromeSeleniumActions;
5 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig;
6 | import com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException;
7 | import org.openqa.selenium.Platform;
8 | import org.openqa.selenium.WebDriver;
9 | import org.openqa.selenium.chrome.ChromeDriver;
10 | import org.openqa.selenium.chrome.ChromeDriverService;
11 | import org.openqa.selenium.chrome.ChromeOptions;
12 | import org.openqa.selenium.logging.LogEntries;
13 | import org.openqa.selenium.logging.LogType;
14 | import org.openqa.selenium.logging.LoggingPreferences;
15 | import org.openqa.selenium.remote.CapabilityType;
16 | import org.openqa.selenium.remote.DesiredCapabilities;
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 |
20 | import javax.annotation.Nullable;
21 | import java.io.File;
22 | import java.io.IOException;
23 | import java.util.*;
24 | import java.util.logging.Level;
25 |
26 | public class ChromeBrowser extends WebBrowser {
27 | private Optional> options;
28 |
29 | public ChromeBrowser(String baseTestUrl,
30 | TimeoutsConfig timeouts,
31 | Optional driverPath,
32 | Optional browserBinaryPath,
33 | Optional browserVersion,
34 | Optional browserLocale,
35 | Optional startWindowWidth,
36 | Optional startWindowHeight,
37 | Optional browserLogLevel,
38 | Optional browserLogFile,
39 | Optional platform,
40 | Optional> options) {
41 |
42 | super(baseTestUrl, timeouts, driverPath, browserBinaryPath, browserVersion, browserLocale,
43 | startWindowWidth, startWindowHeight, browserLogLevel, browserLogFile, platform);
44 | this.options = options;
45 | }
46 |
47 | private static final Logger logger = LoggerFactory.getLogger(ChromeBrowser.class);
48 |
49 |
50 | @Override
51 | public WebBrowserType getBrowserType() {
52 | return WebBrowserType.CHROME;
53 | }
54 |
55 | @Override
56 | public LoggingPreferences getLoggingPreferences() {
57 | Level level = getLogLevel();
58 | LoggingPreferences loggingPreferences = new LoggingPreferences();
59 | loggingPreferences.enable(LogType.BROWSER, level);
60 | loggingPreferences.enable(LogType.DRIVER, level);
61 | return loggingPreferences;
62 | }
63 |
64 | @Override
65 | public DesiredCapabilities getDesiredCapabilities() {
66 | DesiredCapabilities desiredCapabilities = DesiredCapabilities.chrome();
67 |
68 | setCommonWebBrowserCapabilities(desiredCapabilities);
69 |
70 | desiredCapabilities.setCapability(CapabilityType.ForSeleniumServer.ENSURING_CLEAN_SESSION, true);
71 |
72 | // If the locale option is present and is not empty, then set this option in Chromedriver
73 | Optional browserLocale = getBrowserLocale();
74 | if (browserLocale.isPresent() && !browserLocale.get().isEmpty()) {
75 | Map chromePrefs = Maps.newHashMap();
76 | chromePrefs.put("intl.accept_languages", browserLocale.get());
77 | desiredCapabilities.setCapability("chrome.prefs", chromePrefs);
78 | }
79 |
80 | // If the browser binary path is present and not empty, then set this as the Chrome Binary file
81 | Optional browserBinaryPath = getBrowserBinaryPath();
82 | if (browserBinaryPath.isPresent() && !browserBinaryPath.get().isEmpty()) {
83 | desiredCapabilities.setCapability("chrome.binary", browserBinaryPath.get());
84 | }
85 |
86 | // ChromeOptions
87 | ChromeOptions chromeOptions = new ChromeOptions();
88 |
89 | // This tells Chromedriver we're running tests.
90 | // This eliminates the banner with the message "You are using an unsupported command-line flag --ignore-certificate-errors"
91 | if(options.isPresent()) {
92 | if (!options.get().contains("test-type")) {
93 | options.get().add("test-type");
94 | }
95 |
96 | chromeOptions.addArguments(options.get());
97 | desiredCapabilities.setCapability(ChromeOptions.CAPABILITY, chromeOptions);
98 | }
99 | return desiredCapabilities;
100 | }
101 |
102 | @Override
103 | public ChromeSeleniumActions getActions() {
104 | return new ChromeSeleniumActions(this);
105 | }
106 |
107 | @Override
108 | protected WebDriver createWebDriver() throws JiveWebDriverException {
109 | Optional driverPath = getWebDriverPath();
110 | Optional browserLogFile = getBrowserLogFile();
111 |
112 | ChromeDriverService.Builder builder = new ChromeDriverService.Builder()
113 | .usingAnyFreePort();
114 |
115 | if (driverPath.isPresent() && !driverPath.get().isEmpty()) {
116 | File chromedriverFile = new File(driverPath.get());
117 | builder.usingDriverExecutable(chromedriverFile);
118 | }
119 |
120 | if (browserLogFile.isPresent() && !browserLogFile.get().isEmpty()) {
121 | builder.withLogFile(new File(browserLogFile.get()));
122 | }
123 |
124 | ChromeDriverService service = builder.build();
125 |
126 | try {
127 | service.start();
128 | } catch (IOException e) {
129 | throw new JiveWebDriverException("Error starting Chrome driver service", e);
130 | }
131 | return new ChromeDriver(service, getDesiredCapabilities());
132 | }
133 |
134 | @Nullable
135 | public LogEntries getBrowserLogEntries() {
136 | if (webDriver == null) {
137 | logger.info("WebDriver was null in ChromeBrowser#getBrowserLogEntries! Returning null.");
138 | return null;
139 | }
140 | logger.debug("Getting available log types...");
141 | Set availableLogTypes = webDriver.manage().logs().getAvailableLogTypes();
142 | logger.debug("Found log types: {}", availableLogTypes);
143 | if (availableLogTypes == null || !availableLogTypes.contains(LogType.BROWSER)) {
144 | return null;
145 | }
146 | LogEntries logs = webDriver.manage().logs().get(LogType.BROWSER);
147 | logger.info("Success - obtained Browser logs for a local ChromeBrowser!");
148 | return logs;
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/web/FirefoxBrowser.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.web;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.actions.FirefoxSeleniumActions;
4 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig;
5 | import org.openqa.selenium.Platform;
6 | import org.openqa.selenium.WebDriver;
7 | import org.openqa.selenium.firefox.FirefoxBinary;
8 | import org.openqa.selenium.firefox.FirefoxDriver;
9 | import org.openqa.selenium.firefox.FirefoxProfile;
10 | import org.openqa.selenium.logging.LogEntries;
11 | import org.openqa.selenium.logging.LogType;
12 | import org.openqa.selenium.remote.CapabilityType;
13 | import org.openqa.selenium.remote.DesiredCapabilities;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 |
17 | import javax.annotation.Nullable;
18 | import java.io.File;
19 | import java.util.Optional;
20 | import java.util.Set;
21 |
22 | public class FirefoxBrowser extends WebBrowser {
23 |
24 | public FirefoxBrowser(String baseTestUrl,
25 | TimeoutsConfig timeoutsConfig,
26 | Optional webDriverPath,
27 | Optional browserBinaryPath,
28 | Optional browserVersion,
29 | Optional browserLocale,
30 | Optional startWindowWidth,
31 | Optional startWindowHeight,
32 | Optional platform) {
33 |
34 | super(baseTestUrl, timeoutsConfig, webDriverPath, browserBinaryPath, browserVersion, browserLocale, startWindowWidth, startWindowHeight, platform);
35 | }
36 |
37 | private static final Logger logger = LoggerFactory.getLogger(FirefoxBrowser.class);
38 |
39 |
40 | @Override
41 | public WebBrowserType getBrowserType() {
42 | return WebBrowserType.FIREFOX;
43 | }
44 |
45 | @Override
46 | public DesiredCapabilities getDesiredCapabilities() {
47 | DesiredCapabilities desiredCapabilities = DesiredCapabilities.firefox();
48 |
49 | setCommonWebBrowserCapabilities(desiredCapabilities);
50 |
51 | desiredCapabilities.setCapability(CapabilityType.ForSeleniumServer.ENSURING_CLEAN_SESSION, true);
52 |
53 | FirefoxProfile profile = new FirefoxProfile();
54 | profile.setEnableNativeEvents(true);
55 | desiredCapabilities.setCapability(FirefoxDriver.PROFILE, profile);
56 |
57 | // If the browerBinaryPath is present, and it points to a real file, then set this as the Firefox Binary
58 | Optional browserBinaryPath = getBrowserBinaryPath();
59 | if (browserBinaryPath.isPresent() && !browserBinaryPath.get().isEmpty()) {
60 | final String browserBinaryPathStr = browserBinaryPath.get();
61 | File file = new File(browserBinaryPathStr);
62 | if (file.exists()) {
63 | desiredCapabilities.setCapability(FirefoxDriver.BINARY, new FirefoxBinary(file));
64 | }
65 | }
66 |
67 | return desiredCapabilities;
68 | }
69 |
70 | @Override
71 | protected WebDriver createWebDriver() {
72 | DesiredCapabilities desiredCapabilities = getDesiredCapabilities();
73 | return new FirefoxDriver(desiredCapabilities);
74 | }
75 |
76 | @Override
77 | public FirefoxSeleniumActions getActions() {
78 | return new FirefoxSeleniumActions(this);
79 | }
80 |
81 | @Nullable
82 | public LogEntries getBrowserLogEntries() {
83 | if (webDriver == null) {
84 | logger.info("WebDriver was null in FirefoxBrowser#getBrowserLogEntries! Returning null.");
85 | return null;
86 | }
87 | logger.debug("Getting available log types...");
88 | Set availableLogTypes = webDriver.manage().logs().getAvailableLogTypes();
89 | logger.debug("Found log types: {}", availableLogTypes);
90 | if (availableLogTypes == null || !availableLogTypes.contains(LogType.BROWSER)) {
91 | return null;
92 | }
93 | LogEntries logs = webDriver.manage().logs().get(LogType.BROWSER);
94 | logger.info("Success - obtained Browser logs for a local FirefoxBrowser!");
95 | return logs;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/web/InternetExplorerBrowser.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.web;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.actions.InternetExplorerActions;
4 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig;
5 | import com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException;
6 | import org.openqa.selenium.Platform;
7 | import org.openqa.selenium.WebDriver;
8 | import org.openqa.selenium.ie.InternetExplorerDriver;
9 | import org.openqa.selenium.ie.InternetExplorerDriverLogLevel;
10 | import org.openqa.selenium.logging.LogEntries;
11 | import org.openqa.selenium.remote.CapabilityType;
12 | import org.openqa.selenium.remote.DesiredCapabilities;
13 |
14 | import javax.annotation.Nullable;
15 | import java.util.Optional;
16 | import java.util.logging.Level;
17 |
18 | public class InternetExplorerBrowser extends WebBrowser {
19 | public InternetExplorerBrowser(String baseTestUrl,
20 | TimeoutsConfig timeouts,
21 | Optional driverPath,
22 | Optional browserBinaryPath,
23 | Optional browserVersion,
24 | Optional browserLocale,
25 | Optional startWindowWidth,
26 | Optional startWindowHeight,
27 | Optional browserLogLevel,
28 | Optional browserLogFile,
29 | Optional platform) {
30 | super(baseTestUrl, timeouts, driverPath, browserBinaryPath, browserVersion, browserLocale, startWindowWidth, startWindowHeight, browserLogLevel, browserLogFile, platform);
31 | }
32 |
33 | @Override
34 | public WebBrowserType getBrowserType() {
35 | return WebBrowserType.IE;
36 | }
37 |
38 | @Override
39 | public DesiredCapabilities getDesiredCapabilities() {
40 | DesiredCapabilities desiredCapabilities = DesiredCapabilities.internetExplorer();
41 |
42 | setCommonWebBrowserCapabilities(desiredCapabilities);
43 |
44 | desiredCapabilities.setCapability(CapabilityType.ForSeleniumServer.ENSURING_CLEAN_SESSION, true);
45 | desiredCapabilities.setCapability(InternetExplorerDriver.NATIVE_EVENTS, false);
46 | desiredCapabilities.setCapability(InternetExplorerDriver.IGNORE_ZOOM_SETTING, true);
47 | desiredCapabilities.setCapability(InternetExplorerDriver.IE_ENSURE_CLEAN_SESSION, true);
48 | desiredCapabilities.setCapability(InternetExplorerDriver.ENABLE_PERSISTENT_HOVERING, true);
49 |
50 |
51 | Level logLevel = getLogLevel();
52 | desiredCapabilities.setCapability(InternetExplorerDriver.LOG_LEVEL, convertJavaLogLevelToIeLogLevel(logLevel.toString()));
53 |
54 | Optional browserLogFile = getBrowserLogFile();
55 | if (browserLogFile.isPresent() && !browserLogFile.get().isEmpty()) {
56 | desiredCapabilities.setCapability(InternetExplorerDriver.LOG_FILE, browserLogFile.get());
57 | }
58 |
59 | return desiredCapabilities;
60 | }
61 |
62 | private static String convertJavaLogLevelToIeLogLevel(String javaLogLevel) {
63 | if ("WARN".equals(javaLogLevel)) {
64 | javaLogLevel = "WARNING";
65 | }
66 | Level javaLevel = Level.parse(javaLogLevel);
67 | if (Level.ALL.equals(javaLevel)) {
68 | return InternetExplorerDriverLogLevel.TRACE.toString();
69 | } else if (Level.CONFIG.equals(javaLevel)) {
70 | return InternetExplorerDriverLogLevel.TRACE.toString();
71 | } else if (Level.FINE.equals(javaLevel)) {
72 | return InternetExplorerDriverLogLevel.DEBUG.toString();
73 | } else if (Level.FINER.equals(javaLevel)) {
74 | return InternetExplorerDriverLogLevel.TRACE.toString();
75 | } else if (Level.FINEST.equals(javaLevel)) {
76 | return InternetExplorerDriverLogLevel.TRACE.toString();
77 | } else if (Level.INFO.equals(javaLevel)) {
78 | return InternetExplorerDriverLogLevel.INFO.toString();
79 | } else if (Level.OFF.equals(javaLevel)) {
80 | return InternetExplorerDriverLogLevel.FATAL.toString();
81 | } else if (Level.SEVERE.equals(javaLevel)) {
82 | return InternetExplorerDriverLogLevel.ERROR.toString();
83 | } else if (Level.WARNING.equals(javaLevel)) {
84 | return InternetExplorerDriverLogLevel.WARN.toString();
85 | }
86 | return InternetExplorerDriverLogLevel.INFO.toString();
87 | }
88 |
89 | @Override
90 | public InternetExplorerActions getActions() {
91 | return new InternetExplorerActions(this);
92 | }
93 |
94 | @Override
95 | protected WebDriver createWebDriver() throws JiveWebDriverException {
96 | return new InternetExplorerDriver(getDesiredCapabilities());
97 | }
98 |
99 | @Nullable
100 | public LogEntries getBrowserLogEntries() {
101 | return null; // Can't get Console logs for Internet Explorer, at least not remotely.
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/web/RemoteBrowser.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.web;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.actions.SeleniumActions;
4 | import com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException;
5 | import org.apache.commons.io.FileUtils;
6 | import org.openqa.selenium.OutputType;
7 | import org.openqa.selenium.TakesScreenshot;
8 | import org.openqa.selenium.WebDriver;
9 | import org.openqa.selenium.logging.LogEntries;
10 | import org.openqa.selenium.logging.LogType;
11 | import org.openqa.selenium.remote.Augmenter;
12 | import org.openqa.selenium.remote.DesiredCapabilities;
13 | import org.openqa.selenium.remote.LocalFileDetector;
14 | import org.openqa.selenium.remote.RemoteWebDriver;
15 | import org.slf4j.Logger;
16 | import org.slf4j.LoggerFactory;
17 |
18 | import javax.annotation.Nullable;
19 | import java.io.File;
20 | import java.io.IOException;
21 | import java.net.MalformedURLException;
22 | import java.net.URL;
23 | import java.util.Set;
24 | import java.util.logging.Level;
25 |
26 | /**
27 | * Represents a RemoteBrowser, i.e. running a Browser on a Selenium Node controlled by a Selenium Hub.
28 | * To create an instance, pass in the "delegate" browser and the URL to the Selenium Hub.
29 | * Example Selenium Hub URL: http://hub.my.company.com:4444/wd/hub
30 | *
31 | * See http://code.google.com/p/selenium/wiki/Grid2
32 | */
33 | public class RemoteBrowser extends WebBrowser {
34 | protected WebBrowser delegate;
35 | protected String seleniumHubURL;
36 | private static final Logger logger = LoggerFactory.getLogger(RemoteBrowser.class);
37 |
38 |
39 | public RemoteBrowser(WebBrowser delegate, String seleniumHubURL) {
40 | super(delegate.getBaseTestUrl(),
41 | delegate.getTimeouts(),
42 | delegate.getWebDriverPath(),
43 | delegate.getBrowserBinaryPath(),
44 | delegate.getBrowserVersion(),
45 | delegate.getBrowserLocale(),
46 | delegate.getStartWindowWidth(),
47 | delegate.getStartWindowHeight(), delegate.getBrowserLogLevel(), delegate.getBrowserLogFile(), delegate.getPlatform());
48 | this.delegate = delegate;
49 | this.seleniumHubURL = seleniumHubURL;
50 | }
51 |
52 | @Override
53 | public WebBrowserType getBrowserType() {
54 | return delegate.getBrowserType();
55 | }
56 |
57 | @Override
58 | public DesiredCapabilities getDesiredCapabilities() {
59 | return delegate.getDesiredCapabilities();
60 | }
61 |
62 | @Override
63 | protected WebDriver createWebDriver() throws JiveWebDriverException {
64 | try {
65 | RemoteWebDriver driver = new RemoteWebDriver(new URL(seleniumHubURL), delegate.getDesiredCapabilities());
66 | Level level = getLogLevel();
67 | driver.setLogLevel(level);
68 | driver.setFileDetector(new LocalFileDetector()); // Allow to upload local files to remote webdriver
69 | // https://code.google.com/p/selenium/source/browse/java/client/src/org/openqa/selenium/remote/LocalFileDetector.java
70 | return driver;
71 | } catch (MalformedURLException e) {
72 | throw new JiveWebDriverException("Invalid Selenium Hub URL given: " + seleniumHubURL, e);
73 | }
74 | }
75 |
76 | @Override
77 | public SeleniumActions getActions() {
78 | SeleniumActions actions = delegate.getActions();
79 | actions.setBrowser(this); //We are running remotely, so the Actions should use the RemoteBrowser and RemoteWebDriver
80 | return actions;
81 | }
82 |
83 | /**
84 | * Get the Browser logs (console logs) from the Remote Browser.
85 | * Added more logging to debug a 5 minute gap in time we saw in a recent failed test run.
86 | * The issue is probably unrelated to this, but it can't hurt to log more data so we can rule it out.
87 | *
88 | * @return - a {@link org.openqa.selenium.logging.LogEntries} with all the log entries since last time this was called.
89 | */
90 | @Nullable
91 | public LogEntries getBrowserLogEntries() {
92 | if (delegate.getBrowserType() == WebBrowserType.IE) {
93 | logger.info("IE does not support getting Browser Logs remotely. Returning null from getBrowserLogEntries");
94 | return null;
95 | }
96 | try {
97 | if (webDriver == null) {
98 | logger.info("The web driver was null in getBrowserLogEntries. Returning null.");
99 | return null;
100 | }
101 | logger.debug("Getting the available log types from remote Selenium node...");
102 | Set availableLogTypes = webDriver.manage().logs().getAvailableLogTypes();
103 |
104 | logger.debug("Found available log types: {}", String.valueOf(availableLogTypes));
105 |
106 | if (availableLogTypes == null || !availableLogTypes.contains(LogType.BROWSER)) {
107 | logger.info("{} log type not allowed. Returning null.", LogType.BROWSER);
108 | return null;
109 | }
110 | logger.debug("Fetching logs from remote server...");
111 |
112 | LogEntries logs = webDriver.manage().logs().get(LogType.BROWSER);
113 |
114 | logger.info("Success getting remote logs!");
115 |
116 | return logs;
117 | } catch (Exception e) {
118 | // If some error occurs making the HTTP request to get logs, just return null.
119 | logger.info("Error retrieving remote logs: " + e.getMessage());
120 | return null;
121 | }
122 | }
123 |
124 | /**
125 | * Save a screenshot in PNG format to given file name.
126 | *
127 | * @param filename
128 | * @return - a File representing the saved screenshot.
129 | */
130 | @Override
131 | public File saveScreenshotToFile(String filename) {
132 | TakesScreenshot screenshotDriver;
133 | screenshotDriver = (TakesScreenshot) new Augmenter().augment(getWebDriver());
134 | File scrFile = screenshotDriver.getScreenshotAs(OutputType.FILE);
135 | // Now you can do whatever you need to do with it, for example copy somewhere
136 | File outFile = new File(filename);
137 | try {
138 | FileUtils.copyFile(scrFile, outFile);
139 | } catch (IOException e) {
140 | logger.error("Error saving screenshot!", e);
141 | }
142 | return outFile;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/web/SafariBrowser.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.web;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.actions.SafariSeleniumActions;
4 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig;
5 | import com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException;
6 | import org.openqa.selenium.Platform;
7 | import org.openqa.selenium.WebDriver;
8 | import org.openqa.selenium.logging.LogEntries;
9 | import org.openqa.selenium.logging.LogType;
10 | import org.openqa.selenium.logging.LoggingPreferences;
11 | import org.openqa.selenium.remote.CapabilityType;
12 | import org.openqa.selenium.remote.DesiredCapabilities;
13 | import org.openqa.selenium.safari.SafariDriver;
14 | import org.openqa.selenium.safari.SafariOptions;
15 | import org.slf4j.Logger;
16 | import org.slf4j.LoggerFactory;
17 |
18 | import javax.annotation.Nullable;
19 | import java.util.Optional;
20 | import java.util.Set;
21 | import java.util.logging.Level;
22 |
23 | public class SafariBrowser extends WebBrowser {
24 | public SafariBrowser(String baseTestUrl,
25 | TimeoutsConfig timeouts,
26 | Optional driverPath,
27 | Optional browserBinaryPath,
28 | Optional browserVersion,
29 | Optional browserLocale,
30 | Optional startWindowWidth,
31 | Optional startWindowHeight,
32 | Optional browserLogLevel,
33 | Optional browserLogFile,
34 | Optional platform) {
35 |
36 | super(baseTestUrl, timeouts, driverPath, browserBinaryPath, browserVersion, browserLocale,
37 | startWindowWidth, startWindowHeight, browserLogLevel, browserLogFile, platform);
38 | }
39 |
40 | private static final Logger logger = LoggerFactory.getLogger(SafariBrowser.class);
41 |
42 |
43 | @Override
44 | public WebBrowserType getBrowserType() {
45 | return WebBrowserType.SAFARI;
46 | }
47 |
48 | @Override
49 | public LoggingPreferences getLoggingPreferences() {
50 | Level level = getLogLevel();
51 | LoggingPreferences loggingPreferences = new LoggingPreferences();
52 | loggingPreferences.enable(LogType.BROWSER, level);
53 | loggingPreferences.enable(LogType.DRIVER, level);
54 | return loggingPreferences;
55 | }
56 |
57 | @Override
58 | public DesiredCapabilities getDesiredCapabilities() {
59 | DesiredCapabilities desiredCapabilities = DesiredCapabilities.safari();
60 |
61 | setCommonWebBrowserCapabilities(desiredCapabilities);
62 |
63 | desiredCapabilities.setCapability(CapabilityType.ForSeleniumServer.ENSURING_CLEAN_SESSION, true);
64 |
65 | SafariOptions safariOptions = new SafariOptions();
66 | safariOptions.setUseCleanSession(true);
67 |
68 | // Selenium seems to be broken if we specify SafariOptions for a RemoteWebDriver.
69 | // java.lang.ClassCastException: org.json.JSONObject cannot be cast to java.lang.String
70 | // at org.openqa.selenium.remote.BeanToJsonConverter.convertObject(BeanToJsonConverter.java:202)
71 |
72 | // desiredCapabilities.setCapability(SafariOptions.CAPABILITY, safariOptions);
73 |
74 | return desiredCapabilities;
75 | }
76 |
77 | @Override
78 | public SafariSeleniumActions getActions() {
79 | return new SafariSeleniumActions(this);
80 | }
81 |
82 | @Override
83 | protected WebDriver createWebDriver() throws JiveWebDriverException {
84 |
85 | return new SafariDriver(getDesiredCapabilities());
86 | }
87 |
88 | @Nullable
89 | public LogEntries getBrowserLogEntries() {
90 | if (webDriver == null) {
91 | logger.info("WebDriver was null in ChromeBrowser#getBrowserLogEntries! Returning null.");
92 | return null;
93 | }
94 | logger.debug("Getting available log types...");
95 | Set availableLogTypes = webDriver.manage().logs().getAvailableLogTypes();
96 | logger.debug("Found log types: {}", availableLogTypes);
97 | if (availableLogTypes == null || !availableLogTypes.contains(LogType.BROWSER)) {
98 | return null;
99 | }
100 | LogEntries logs = webDriver.manage().logs().get(LogType.BROWSER);
101 | logger.info("Success - obtained Browser logs for a local ChromeBrowser!");
102 | return logs;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/web/WebBrowser.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.web;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.browser.Browser;
4 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig;
5 | import com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException;
6 | import com.jivesoftware.selenium.pagefactory.framework.pages.BaseTopLevelPage;
7 | import com.jivesoftware.selenium.pagefactory.framework.pages.TopLevelPage;
8 | import com.jivesoftware.selenium.pagefactory.framework.webservice.EndpointBuilder;
9 | import org.openqa.selenium.Dimension;
10 | import org.openqa.selenium.Platform;
11 | import org.openqa.selenium.WebDriver;
12 | import org.openqa.selenium.logging.LogEntries;
13 | import org.openqa.selenium.logging.LogType;
14 | import org.openqa.selenium.logging.LoggingPreferences;
15 | import org.openqa.selenium.remote.CapabilityType;
16 | import org.openqa.selenium.remote.DesiredCapabilities;
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 |
20 | import javax.annotation.Nullable;
21 | import java.net.URI;
22 | import java.util.Optional;
23 | import java.util.concurrent.TimeUnit;
24 | import java.util.logging.Level;
25 |
26 | /**
27 | * Base Browser class.
28 | * Contains a lot of the configuration that is common across browsers.
29 | * Subclasses must implement getBrowserType, getDesiredCapabilities, isRemote, and getActions
30 | */
31 | public abstract class WebBrowser extends Browser {
32 | private static final Logger logger = LoggerFactory.getLogger(WebBrowser.class);
33 |
34 | private final Optional webDriverPath;
35 | private final Optional browserBinaryPath;
36 | private final Optional browserVersion;
37 | private final Optional browserLocale;
38 | private final Optional startWindowWidth;
39 | private final Optional startWindowHeight;
40 | private final Optional browserLogLevel;
41 | private final Optional browserLogFile;
42 | private final Optional platform;
43 |
44 | public WebBrowser(String baseTestUrl,
45 | TimeoutsConfig timeouts,
46 | Optional webDriverPath,
47 | Optional browserBinaryPath,
48 | Optional browserVersion,
49 | Optional browserLocale,
50 | Optional startWindowWidth,
51 | Optional startWindowHeight,
52 | Optional platform) {
53 |
54 | this(baseTestUrl, timeouts, webDriverPath, browserBinaryPath, browserVersion, browserLocale,
55 | startWindowWidth, startWindowHeight,
56 | Optional.empty(), Optional.empty(), platform);
57 |
58 | }
59 |
60 | public WebBrowser(String baseTestUrl,
61 | TimeoutsConfig timeouts,
62 | Optional webDriverPath,
63 | Optional browserBinaryPath,
64 | Optional browserVersion,
65 | Optional browserLocale,
66 | Optional startWindowWidth,
67 | Optional startWindowHeight,
68 | Optional browserLogLevel,
69 | Optional browserLogFile,
70 | Optional platform) {
71 | super(baseTestUrl, timeouts);
72 | this.webDriverPath = webDriverPath;
73 | this.browserBinaryPath = browserBinaryPath;
74 | this.browserVersion = browserVersion;
75 | this.browserLocale = browserLocale;
76 | this.startWindowWidth = startWindowWidth;
77 | this.startWindowHeight = startWindowHeight;
78 | this.browserLogLevel = browserLogLevel;
79 | this.browserLogFile = browserLogFile;
80 | this.platform = platform;
81 | }
82 |
83 | /**
84 | * Initialize the browser. This creates a web driver instance, which opens the Browser to a blank page.
85 | * Resize the window to the configured values.
86 | *
87 | * @throws JiveWebDriverException
88 | */
89 | public void initializeBrowser() throws JiveWebDriverException {
90 | this.webDriver = createWebDriver();
91 | if (startWindowWidth.isPresent() && startWindowHeight.isPresent()) {
92 | this.webDriver.manage().window().setSize(new Dimension(startWindowWidth.get(), startWindowHeight.get()));
93 | }
94 | // Safari web driver doesn't support setting timeouts.
95 | if (getBrowserType() != WebBrowserType.SAFARI) {
96 | this.webDriver.manage().timeouts().pageLoadTimeout(getPageTimeoutSeconds(), TimeUnit.SECONDS);
97 | this.webDriver.manage().timeouts().implicitlyWait(getImplicitWaitTimeoutMillis(), TimeUnit.MILLISECONDS);
98 | }
99 | logger.info("SUCCESS - Created WebBrowser of type {}: {}", getBrowserType(), webDriver);
100 | }
101 |
102 | public abstract WebBrowserType getBrowserType();
103 |
104 | public abstract DesiredCapabilities getDesiredCapabilities();
105 |
106 | public LoggingPreferences getLoggingPreferences() {
107 | Level level = getLogLevel();
108 | LoggingPreferences loggingPreferences = new LoggingPreferences();
109 | loggingPreferences.enable(LogType.BROWSER, level);
110 | loggingPreferences.enable(LogType.CLIENT, level);
111 | loggingPreferences.enable(LogType.DRIVER, level);
112 | loggingPreferences.enable(LogType.SERVER, level);
113 | return loggingPreferences;
114 | }
115 |
116 | public Optional getStartWindowWidth() {
117 | return startWindowWidth;
118 | }
119 |
120 | public Optional getStartWindowHeight() {
121 | return startWindowHeight;
122 | }
123 |
124 | public Optional getWebDriverPath() {
125 | return webDriverPath;
126 | }
127 |
128 | public Optional getBrowserBinaryPath() {
129 | return browserBinaryPath;
130 | }
131 |
132 | public Optional getBrowserVersion() {
133 | return browserVersion;
134 | }
135 |
136 | public Optional getBrowserLocale() {
137 | return browserLocale;
138 | }
139 |
140 | public Optional getBrowserLogLevel() {
141 | return browserLogLevel;
142 | }
143 |
144 | public Level getLogLevel() {
145 | return browserLogLevel.isPresent() ? browserLogLevel.get() : Level.WARNING;
146 | }
147 |
148 | public Optional getBrowserLogFile() {
149 | return browserLogFile;
150 | }
151 |
152 | public Optional getPlatform() {
153 | return platform;
154 | }
155 |
156 | public TimeoutsConfig getTimeouts() {
157 | return timeouts;
158 | }
159 |
160 | /**
161 | * Opens a new page in the Browser by URL. An absolute URL or the path can be provided.
162 | * If a path is provided, then the baseTestUrl provided when creating the browser will be used as the
163 | * base of the URL.
164 | *
165 | * Invalidates the cached page and loads a fresh new page.
166 | *
167 | * @param href - the href from a link, which may be a relative path from baseTestUrl or may be absolute
168 | * @return - a generic {@link com.jivesoftware.selenium.pagefactory.framework.pages.BaseTopLevelPage}
169 | * page object. To open a page with more specific functionality, you must extend
170 | * {@link com.jivesoftware.selenium.pagefactory.framework.pages.BaseTopLevelPage} and then
171 | * call {@link #openPageByURL(String, Class)}.
172 | */
173 | public TopLevelPage openPageByURL(String href) {
174 | return openPageByURL(href, BaseTopLevelPage.class);
175 | }
176 |
177 | /**
178 | * Opens a new page in the Browser by URL. An absolute URL or the path can be provided.
179 | *
180 | * Invalidates the cached page and loads a fresh new page.
181 | *
182 | * @param uri - the href from a link, which may be a relative path from baseTestUrl or may be absolute
183 | * @param pageClass - the {@link com.jivesoftware.selenium.pagefactory.framework.pages.TopLevelPage} class to load.
184 | */
185 | public T openPageByURL(URI uri, Class pageClass) {
186 | URI absoluteURI;
187 | if (uri.isAbsolute()) {
188 | absoluteURI = uri;
189 | } else {
190 | String fullURIStr = EndpointBuilder.uri(baseTestUrl, "/", uri.toString());
191 | absoluteURI = URI.create(fullURIStr);
192 | }
193 | logger.info("Opening web page by URL {}", absoluteURI);
194 | runLeavePageHook();
195 | invalidateCachedPage();
196 | T page = PAGE_UTILS.loadPageFromURL(absoluteURI, pageClass, getWebDriver(), getActions());
197 | setCachedPage(page);
198 | return page;
199 | }
200 |
201 | /**
202 | * Opens a new page in the Browser by URL. An absolute URL or the path can be provided.
203 | *
204 | * Invalidates the cached page and loads a fresh new page.
205 | *
206 | * @param href - the href from a link, which may be a relative path from baseTestUrl or may be absolute
207 | * @param pageClass - the {@link com.jivesoftware.selenium.pagefactory.framework.pages.TopLevelPage} class to load.
208 | */
209 | public T openPageByURL(String href, Class pageClass) {
210 | URI uri = URI.create(href);
211 | return openPageByURL(uri, pageClass);
212 | }
213 |
214 | /**
215 | * Refresh the current page, without giving back a newly initialized Page object.
216 | */
217 | public void refreshPage() {
218 | runLeavePageHook();
219 | webDriver.navigate().refresh();
220 | if (optionalCachedPage.isPresent()) {
221 | TopLevelPage cachedPage = optionalCachedPage.get().getCachedPage();
222 | cachedPage.refreshElements();
223 | }
224 | }
225 |
226 | /**
227 | * @param pageClass - the class of the expected Page after refreshing.
228 | */
229 | public T refreshPage(Class pageClass) {
230 | runLeavePageHook();
231 | invalidateCachedPage();
232 | webDriver.navigate().refresh();
233 | T page = loadTopLevelPage(pageClass);
234 | setCachedPage(page);
235 | return page;
236 | }
237 |
238 | public void cleanSession() {
239 | webDriver.manage().deleteAllCookies();
240 | }
241 |
242 | @Nullable
243 | public abstract LogEntries getBrowserLogEntries();
244 |
245 | /**
246 | * Helper to set properties of the DesiredCapabilities that are common across all browsers.
247 | * @param desiredCapabilities
248 | */
249 | protected void setCommonWebBrowserCapabilities(DesiredCapabilities desiredCapabilities) {
250 | // If a required version is present, then set this as a desired capability. Only affects Remote browsers.
251 | Optional browserVersion = getBrowserVersion();
252 | if (browserVersion.isPresent() && !browserVersion.get().isEmpty()) {
253 | desiredCapabilities.setCapability(CapabilityType.VERSION, browserVersion.get());
254 | }
255 |
256 | // Set logging preferences.
257 | LoggingPreferences loggingPreferences = getLoggingPreferences();
258 | desiredCapabilities.setCapability(CapabilityType.LOGGING_PREFS, loggingPreferences);
259 |
260 | // If a platform is specified, set this desired capability. Only affects Remote browsers.
261 | Optional platform = getPlatform();
262 | if (platform.isPresent()) {
263 | desiredCapabilities.setPlatform(platform.get());
264 | }
265 | }
266 | }
267 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/browser/web/WebBrowserType.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.browser.web;
2 |
3 | /**
4 | * Represents the type of Browser being created.
5 | * TODO: Add support for Safari by creating a SafariBrowser class and figure out the correct DesiredCapabilities for configuring Safari.
6 | */
7 | public enum WebBrowserType {
8 | IE, CHROME, FIREFOX, SAFARI, MOBILE;
9 |
10 | public static WebBrowserType forName(String name) {
11 | for (WebBrowserType type: WebBrowserType.values()) {
12 | if (type.toString().equalsIgnoreCase(name)) {
13 | return type;
14 | }
15 | }
16 | throw new IllegalArgumentException("WebBrowserType must be 'IE', 'CHROME', 'FIREFOX', 'SAFARI', or 'MOBILE'");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/config/DefaultTimeouts.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.config;
2 |
3 | /**
4 | * Created by charles.capps on 8/13/14.
5 | *
6 | * Default timeout constants, only for use within this package.
7 | * @see TimeoutType
8 | * @see TimeoutsConfig
9 | */
10 | interface DefaultTimeouts {
11 | public static final int CLICK_TIMEOUT_SECONDS = 5;
12 | public static final int PRESENCE_TIMEOUT_SECONDS = 5;
13 | public static final int POLLING_WITH_REFRESH_TIMEOUT_SECONDS = 30;
14 | public static final int REFRESH_TIMEOUT_SECONDS = 5;
15 | public static final int SHORT_TIMEOUT_SECONDS = 1;
16 | public static final int MEDIUM_TIMEOUT_SECONDS = 5;
17 | public static final int LONG_TIMEOUT_SECONDS = 20;
18 | public static final int PAUSE_BETWEEN_KEYS_MILLIS = 50;
19 | public static final int PAUSE_BETWEEN_TRIES_MILLIS = 200;
20 | public static final int PAUSE_BETWEEN_REFRESH_SECONDS = 5;
21 | public static final int PAGE_LOAD_TIMEOUT_SECONDS = 80;
22 | public static final int PAGE_READY_TIMEOUT_SECONDS = 10;
23 | public static final int IMPLICIT_WAIT_TIMEOUT_MILLIS = 2000;
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/config/TimeoutType.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.config;
2 |
3 | /**
4 | * Created by charles.capps on 8/13/14.
5 | *
6 | * Represents the type of Timeout. This is used rather than allowing Magic Numbers to be used arbitrarily for timeouts.
7 | * All timeouts represent values in seconds.
8 | *
9 | * A TimeoutType is passed into various methods of {@link com.jivesoftware.selenium.pagefactory.framework.actions.SeleniumActions}.
10 | * This indicates whether to use the DEFAULT timeout for the action, or to use a different TimeoutType.
11 | *
12 | * The "DEFAULT" value is special. It causes the timeout used to be the default timeout for the context.
13 | * DEFAULT causes the TimeoutType that is the default for the given method being called to be used.
14 | *
15 | * You want to use DEFAULT in the vast majority of cases. The TimeoutType used for a SeleniumActions method should
16 | * only be overridden when absolutely necessary.
17 | *
18 | * @see com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig
19 | * @see com.jivesoftware.selenium.pagefactory.framework.browser.LocalBrowserBuilder
20 | * @see com.jivesoftware.selenium.pagefactory.framework.browser.RemoteBrowserBuilder
21 | *
22 | */
23 | public enum TimeoutType {
24 | /** Default timeout. The timeout used is context-sensitive based on the method in SeleniumActions you are calling.
25 | * This is what you want to use most of the time. **/
26 | DEFAULT,
27 | /** Timeout to wait for an element to be click-able when attempting to click. **/
28 | CLICK_TIMEOUT,
29 | /** Timeout to wait for an element to be present on the DOM or to be visible. **/
30 | WEB_ELEMENT_PRESENCE_TIMEOUT,
31 | /** Timeout waiting for the page to refresh, or for an element to become stale or removed from the DOM. **/
32 | PAGE_REFRESH_TIMEOUT,
33 | /** Timeout waiting for a new page to load, used to set the internal Selenium page load timeout **/
34 | PAGE_LOAD_TIMEOUT,
35 | /** Timeout waiting for elements to be present on a page after page load **/
36 | PAGE_READY_TIMEOUT,
37 | /** Timeout waiting on anything that requires refreshing the page many times, e.g. something like an Activity Stream.
38 | * Used by SeleniumActions#findElementContainingTextWithRefresh and other methods that refresh the page until something is present. **/
39 | POLLING_WITH_REFRESH_TIMEOUT,
40 | /** Arbitrary short timeout configured by the client. **/
41 | SHORT,
42 | /** Arbitrary medium timeout configured by the client. **/
43 | MEDIUM,
44 | /** Arbitrary long timeout configured by the client. **/
45 | LONG,
46 | /** Fixed timeouts not affected by configuration.
47 | * Usage is discouraged; but this is useful when you need an exact timeout that can't be changed by configuration. **/
48 | ONE_SECOND, TWO_SECONDS, FIVE_SECONDS, TEN_SECONDS, TWENTY_SECONDS, SIXTY_SECONDS, NINETY_SECONDS,
49 | TWO_MINUTES, THREE_MINUTES, FIVE_MINUTES, TEN_MINUTES, THIRTY_MINUTES, SIXTY_MINUTES, NINETY_MINUTES, TWO_HOURS
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/config/TimeoutsConfig.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.config;
2 |
3 | import com.google.common.base.Preconditions;
4 | import com.jivesoftware.selenium.pagefactory.framework.pages.Page;
5 |
6 | import java.util.concurrent.TimeUnit;
7 |
8 | /**
9 | * Represents the timeout configuration used by a {@link com.jivesoftware.selenium.pagefactory.framework.browser.Browser}.
10 | *
11 | * Use TimeoutsConfig.defaultTimeoutsConfig() to get an instance with default timeout values.
12 | *
13 | * Use TimeoutsConfig.builder() to get a Builder that begins with default timeout values.
14 | * Then call builder.build() to get a finalized TimeoutsConfig instance.
15 | *
16 | * @see TimeoutType
17 | */
18 | public final class TimeoutsConfig {
19 |
20 | // Standard timeouts for most common usages
21 | private final int clickTimeoutSeconds;
22 | private final int webElementPresenceTimeoutSeconds;
23 | private final int pollingWithRefreshTimeoutSeconds;
24 | private final int pageRefreshTimeoutSeconds;
25 |
26 | // Arbitrary timeouts configured by client
27 | private final int shortTimeoutSeconds;
28 | private final int mediumTimeoutSeconds;
29 | private final int longTimeoutSeconds;
30 |
31 | // Pauses when polling or entering keys
32 | private final int pauseBetweenKeysMillis;
33 | private final int pauseBetweenTriesMillis;
34 | private final int pauseBetweenRefreshSeconds;
35 |
36 | // Timeouts used for configuring the underlying WebDriver
37 | private final int pageLoadTimeoutSeconds;
38 | private final int pageReadyTimeoutSeconds;
39 | private final int implicitWaitTimeoutMillis;
40 |
41 | /**
42 | * Return a Builder for constructing a TimeoutsConfig instance.
43 | * The Builder is populated with default timeouts, and you can modify them as desired, then call builder.build().
44 | * @return - a {@link com.jivesoftware.selenium.pagefactory.framework.config.TimeoutsConfig.Builder}
45 | */
46 | public static Builder builder() {
47 | return new Builder();
48 | }
49 |
50 | /**
51 | * @return a {@link TimeoutsConfig} with default timeout values
52 | */
53 | public static TimeoutsConfig defaultTimeoutsConfig() {
54 | return new Builder().build();
55 | }
56 |
57 | private TimeoutsConfig(int clickTimeoutSeconds, int webElementPresenceTimeoutSeconds, int pollingWithRefreshTimeoutSeconds,
58 | int pageRefreshTimeoutSeconds, int shortTimeoutSeconds, int mediumTimeoutSeconds, int longTimeoutSeconds,
59 | int pauseBetweenKeysMillis, int pauseBetweenTriesMillis, int pauseBetweenRefreshSeconds,
60 | int pageLoadTimeoutSeconds, int pageReadyTimeoutSeconds, int implicitWaitTimeoutMillis) {
61 | this.clickTimeoutSeconds = clickTimeoutSeconds;
62 | this.webElementPresenceTimeoutSeconds = webElementPresenceTimeoutSeconds;
63 | this.pollingWithRefreshTimeoutSeconds = pollingWithRefreshTimeoutSeconds;
64 | this.pageRefreshTimeoutSeconds = pageRefreshTimeoutSeconds;
65 | this.shortTimeoutSeconds = shortTimeoutSeconds;
66 | this.mediumTimeoutSeconds = mediumTimeoutSeconds;
67 | this.longTimeoutSeconds = longTimeoutSeconds;
68 | this.pauseBetweenKeysMillis = pauseBetweenKeysMillis;
69 | this.pauseBetweenTriesMillis = pauseBetweenTriesMillis;
70 | this.pauseBetweenRefreshSeconds = pauseBetweenRefreshSeconds;
71 | this.pageLoadTimeoutSeconds = pageLoadTimeoutSeconds;
72 | this.pageReadyTimeoutSeconds = pageReadyTimeoutSeconds;
73 | this.implicitWaitTimeoutMillis = implicitWaitTimeoutMillis;
74 | }
75 |
76 | /**
77 | * Return the timeout in seconds for the given TimeoutType.
78 | *
79 | * It doesn't make sense to pass in the DEFAULT timeout type, because that is a context-sensitive timeout.
80 | *
81 | * @param timeout - the TimeoutType (other than DEFAULT) to get the timeout in seconds for.
82 | * @return - the timeout in seconds
83 | */
84 | public int getTimeoutInSeconds(TimeoutType timeout) {
85 | Preconditions.checkNotNull(timeout, "Cannot get timeout for null timeout.");
86 | Preconditions.checkArgument(timeout != TimeoutType.DEFAULT, "Can only get the standard timeout for timeout types other than DEFAULT");
87 | switch (timeout) {
88 |
89 | case CLICK_TIMEOUT:
90 | return getClickTimeoutSeconds();
91 | case WEB_ELEMENT_PRESENCE_TIMEOUT:
92 | return getWebElementPresenceTimeoutSeconds();
93 | case POLLING_WITH_REFRESH_TIMEOUT:
94 | return getPollingWithRefreshTimeoutSeconds();
95 | case PAGE_REFRESH_TIMEOUT:
96 | return getPageRefreshTimeoutSeconds();
97 | case PAGE_LOAD_TIMEOUT:
98 | return getPageLoadTimeoutSeconds();
99 | case PAGE_READY_TIMEOUT:
100 | return getPageReadyTimeoutSeconds();
101 | case SHORT:
102 | return getShortTimeoutSeconds();
103 | case MEDIUM:
104 | return getMediumTimeoutSeconds();
105 | case LONG:
106 | return getLongTimeoutSeconds();
107 | case ONE_SECOND:
108 | return 1;
109 | case TWO_SECONDS:
110 | return 2;
111 | case FIVE_SECONDS:
112 | return 5;
113 | case TEN_SECONDS:
114 | return 10;
115 | case TWENTY_SECONDS:
116 | return 20;
117 | case SIXTY_SECONDS:
118 | return 60;
119 | case NINETY_SECONDS:
120 | return 90;
121 | case TWO_MINUTES:
122 | return (int)TimeUnit.MINUTES.toSeconds(2);
123 | case THREE_MINUTES:
124 | return (int)TimeUnit.MINUTES.toSeconds(3);
125 | case FIVE_MINUTES:
126 | return (int)TimeUnit.MINUTES.toSeconds(5);
127 | case TEN_MINUTES:
128 | return (int)TimeUnit.MINUTES.toSeconds(10);
129 | case THIRTY_MINUTES:
130 | return (int)TimeUnit.MINUTES.toSeconds(30);
131 | case SIXTY_MINUTES:
132 | return (int)TimeUnit.MINUTES.toSeconds(60);
133 | case NINETY_MINUTES:
134 | return (int)TimeUnit.MINUTES.toSeconds(90);
135 | case TWO_HOURS:
136 | return (int)TimeUnit.HOURS.toSeconds(2);
137 | default:
138 | return getWebElementPresenceTimeoutSeconds();
139 | }
140 | }
141 |
142 | public int getClickTimeoutSeconds() {
143 | return clickTimeoutSeconds;
144 | }
145 |
146 | public int getWebElementPresenceTimeoutSeconds() {
147 | return webElementPresenceTimeoutSeconds;
148 | }
149 |
150 | public int getPollingWithRefreshTimeoutSeconds() {
151 | return pollingWithRefreshTimeoutSeconds;
152 | }
153 |
154 | public int getPageRefreshTimeoutSeconds() {
155 | return pageRefreshTimeoutSeconds;
156 | }
157 |
158 | public int getShortTimeoutSeconds() {
159 | return shortTimeoutSeconds;
160 | }
161 |
162 | public int getMediumTimeoutSeconds() {
163 | return mediumTimeoutSeconds;
164 | }
165 |
166 | public int getLongTimeoutSeconds() {
167 | return longTimeoutSeconds;
168 | }
169 |
170 | public int getPauseBetweenKeysMillis() {
171 | return pauseBetweenKeysMillis;
172 | }
173 |
174 | public int getPauseBetweenTriesMillis() {
175 | return pauseBetweenTriesMillis;
176 | }
177 |
178 | public int getPauseBetweenRefreshSeconds() {
179 | return pauseBetweenRefreshSeconds;
180 | }
181 |
182 | public int getPageLoadTimeoutSeconds() {
183 | return pageLoadTimeoutSeconds;
184 | }
185 |
186 | public int getPageReadyTimeoutSeconds() {
187 | return pageReadyTimeoutSeconds;
188 | }
189 |
190 | public int getImplicitWaitTimeoutMillis() {
191 | return implicitWaitTimeoutMillis;
192 | }
193 |
194 | public static final class Builder {
195 | public Builder() {
196 | this.clickTimeoutSeconds = DefaultTimeouts.CLICK_TIMEOUT_SECONDS;
197 | this.webElementPresenceTimeoutSeconds = DefaultTimeouts.PRESENCE_TIMEOUT_SECONDS;
198 | this.pollingWithRefreshTimeoutSeconds = DefaultTimeouts.POLLING_WITH_REFRESH_TIMEOUT_SECONDS;
199 | this.pageRefreshTimeoutSeconds = DefaultTimeouts.REFRESH_TIMEOUT_SECONDS;
200 | this.shortTimeoutSeconds = DefaultTimeouts.SHORT_TIMEOUT_SECONDS;
201 | this.mediumTimeoutSeconds = DefaultTimeouts.MEDIUM_TIMEOUT_SECONDS;
202 | this.longTimeoutSeconds = DefaultTimeouts.LONG_TIMEOUT_SECONDS;
203 | this.pauseBetweenKeysMillis = DefaultTimeouts.PAUSE_BETWEEN_KEYS_MILLIS;
204 | this.pauseBetweenTriesMillis = DefaultTimeouts.PAUSE_BETWEEN_TRIES_MILLIS;
205 | this.pauseBetweenRefreshSeconds = DefaultTimeouts.PAUSE_BETWEEN_REFRESH_SECONDS;
206 | this.pageLoadTimeoutSeconds = DefaultTimeouts.PAGE_LOAD_TIMEOUT_SECONDS;
207 | this.pageReadyTimeoutSeconds = DefaultTimeouts.PAGE_READY_TIMEOUT_SECONDS;
208 | this.implicitWaitTimeoutMillis = DefaultTimeouts.IMPLICIT_WAIT_TIMEOUT_MILLIS;
209 | }
210 |
211 | public TimeoutsConfig build() {
212 | return new TimeoutsConfig(clickTimeoutSeconds,
213 | webElementPresenceTimeoutSeconds,
214 | pollingWithRefreshTimeoutSeconds,
215 | pageRefreshTimeoutSeconds,
216 | shortTimeoutSeconds,
217 | mediumTimeoutSeconds,
218 | longTimeoutSeconds,
219 | pauseBetweenKeysMillis,
220 | pauseBetweenTriesMillis,
221 | pauseBetweenRefreshSeconds,
222 | pageLoadTimeoutSeconds,
223 | pageReadyTimeoutSeconds,
224 | implicitWaitTimeoutMillis);
225 | }
226 |
227 | /**
228 | * Set the timeout waiting for an element to be clickable, in seconds
229 | * @param clickTimeoutSeconds - time in seconds
230 | */
231 | public Builder clickTimeoutSeconds(int clickTimeoutSeconds) {
232 | this.clickTimeoutSeconds = clickTimeoutSeconds;
233 | return this;
234 | }
235 |
236 | /**
237 | * Set the timeout waiting for a web element to be present on the DOM, in seconds.
238 | * @param webElementPresenceTimeoutSeconds - time in seconds
239 | */
240 | public Builder webElementPresenceTimeoutSeconds(int webElementPresenceTimeoutSeconds) {
241 | this.webElementPresenceTimeoutSeconds = webElementPresenceTimeoutSeconds;
242 | return this;
243 | }
244 |
245 | /**
246 | * Set the timeout for long polling activities such as polling for an element to be present by
247 | * refreshing the page repeatedly.
248 | *
249 | * @param pollingWithRefreshTimeoutSeconds - time in seconds
250 | */
251 | public Builder pollingWithRefreshTimeoutSeconds(int pollingWithRefreshTimeoutSeconds) {
252 | this.pollingWithRefreshTimeoutSeconds = pollingWithRefreshTimeoutSeconds;
253 | return this;
254 | }
255 |
256 | /**
257 | * Set the timeout for waiting for an element to become stale or for the page to be refreshed.
258 | * @param pageRefreshTimeoutSeconds - time in seconds
259 | */
260 | public Builder pageRefreshTimeoutSeconds(int pageRefreshTimeoutSeconds) {
261 | this.pageRefreshTimeoutSeconds = pageRefreshTimeoutSeconds;
262 | return this;
263 | }
264 |
265 | /**
266 | * Set the "short" timeout in seconds. Arbitrary timeout configurable by client.
267 | * @param shortTimeoutSeconds - time in seconds
268 | */
269 | public Builder shortTimeoutSeconds(int shortTimeoutSeconds) {
270 | this.shortTimeoutSeconds = shortTimeoutSeconds;
271 | return this;
272 | }
273 |
274 | /**
275 | * Set the "medium" timeout in seconds. Arbitrary timeout configurable by client.
276 | * @param mediumTimeoutSeconds
277 | */
278 | public Builder mediumTimeoutSeconds(int mediumTimeoutSeconds) {
279 | this.mediumTimeoutSeconds = mediumTimeoutSeconds;
280 | return this;
281 | }
282 |
283 | /**
284 | * Set the "long" timeout in seconds. Arbitrary timeout configurable by client.
285 | * @param longTimeoutSeconds
286 | */
287 | public Builder longTimeoutSeconds(int longTimeoutSeconds) {
288 | this.longTimeoutSeconds = longTimeoutSeconds;
289 | return this;
290 | }
291 |
292 | /**
293 | * Set the pause between sending keys when entering text slowly.
294 | * @param pauseBetweenKeysMillis - time in ms
295 | * @return - the Builder
296 | */
297 | public Builder pauseBetweenKeysMillis(int pauseBetweenKeysMillis) {
298 | this.pauseBetweenKeysMillis = pauseBetweenKeysMillis;
299 | return this;
300 | }
301 |
302 | /**
303 | * Set the pause between tries in milliseconds. This is used for pausing between checks to see if an element
304 | * is visible.
305 | * @param pauseBetweenTriesMillis - time in ms
306 | * @return - the Builder
307 | */
308 | public Builder pauseBetweenTriesMillis(int pauseBetweenTriesMillis) {
309 | this.pauseBetweenTriesMillis = pauseBetweenTriesMillis;
310 | return this;
311 | }
312 |
313 | /**
314 | * Set the pause between refreshing the page when polling for something to be present by refreshing the page
315 | * repeatedly.
316 | * @param pauseBetweenRefreshSeconds - time in seconds
317 | * @return - the Builder
318 | */
319 | public Builder pauseBetweenRefreshSeconds(int pauseBetweenRefreshSeconds) {
320 | this.pauseBetweenRefreshSeconds = pauseBetweenRefreshSeconds;
321 | return this;
322 | }
323 |
324 | /**
325 | * Set the timeout waiting for a new page to load in the web browser.
326 | * This is both used by the framework and passed on to the Selenium WebDriver for its configuration.
327 | * @param pageLoadTimeoutSeconds - time in seconds
328 | * @return - the Builder
329 | */
330 | public Builder pageLoadTimoutSeconds(int pageLoadTimeoutSeconds) {
331 | this.pageLoadTimeoutSeconds = pageLoadTimeoutSeconds;
332 | return this;
333 | }
334 |
335 | /**
336 | * Set the timeout waiting for a new page to have elements on the page that are checked after the page loads.
337 | * @see Page#getPageIdentifier()
338 | * This is both used by the framework and passed on to the Selenium WebDriver for its configuration.
339 | * @param pageReadyTimeoutSeconds - time in seconds
340 | * @return - the Builder
341 | */
342 | public Builder pageReadyTimoutSeconds(int pageReadyTimeoutSeconds) {
343 | this.pageReadyTimeoutSeconds = pageReadyTimeoutSeconds;
344 | return this;
345 | }
346 |
347 | /**
348 | * Set the implicit wait timeout for checking if a web element is present.
349 | * This is used when configuring a Selenium WebDriver.
350 | * @param implicitWaitTimeoutMillis
351 | * @return - the Builder
352 | */
353 | public Builder implicitWaitTimeoutMillis(int implicitWaitTimeoutMillis) {
354 | this.implicitWaitTimeoutMillis = implicitWaitTimeoutMillis;
355 | return this;
356 | }
357 |
358 | // Standard timeouts for most common usages, all in seconds
359 | private int clickTimeoutSeconds;
360 | private int webElementPresenceTimeoutSeconds;
361 | private int pollingWithRefreshTimeoutSeconds;
362 | private int pageRefreshTimeoutSeconds;
363 |
364 | // Arbitrary timeouts configured by client, all in seconds
365 | private int shortTimeoutSeconds;
366 | private int mediumTimeoutSeconds;
367 | private int longTimeoutSeconds;
368 |
369 | // Pauses when polling or entering keys
370 | private int pauseBetweenKeysMillis;
371 | private int pauseBetweenTriesMillis;
372 | private int pauseBetweenRefreshSeconds;
373 |
374 | // Timeouts used for configuring the underlying WebDriver
375 | private int pageLoadTimeoutSeconds;
376 | private int pageReadyTimeoutSeconds;
377 | private int implicitWaitTimeoutMillis;
378 | }
379 | }
380 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/exception/InvalidPageUrlException.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.exception;
2 |
3 | public class InvalidPageUrlException extends RuntimeException {
4 | public InvalidPageUrlException(String msg) {
5 | super(msg);
6 | }
7 |
8 | public InvalidPageUrlException(String msg, Exception cause) {
9 | super(msg, cause);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/exception/JiveWebDriverException.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.exception;
2 |
3 | public class JiveWebDriverException extends Exception {
4 | public JiveWebDriverException(String msg) {
5 | super(msg);
6 | }
7 |
8 | public JiveWebDriverException(String msg, Exception e) {
9 | super(msg, e);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/exception/SeleniumActionsException.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.exception;
2 |
3 | public class SeleniumActionsException extends Exception {
4 | public SeleniumActionsException(String msg) {
5 | super(msg);
6 | }
7 |
8 | public SeleniumActionsException(String msg, Exception e) {
9 | super(msg, e);
10 | }
11 | }
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/pages/BaseSubPage.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.pages;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.actions.SeleniumActions;
4 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutType;
5 | import org.openqa.selenium.By;
6 | import org.openqa.selenium.support.PageFactory;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import javax.annotation.Nullable;
11 |
12 | /**
13 | * Base class for a SubPage. Implements the default pageLoadHook that waits for the page identifier to be present.
14 | * Subclasses should call super.pageLoadHook() if they want to wait on the page identifier.
15 | */
16 | public class BaseSubPage implements SubPage {
17 | @SuppressWarnings("unused")
18 | private static Logger logger = LoggerFactory.getLogger(BaseSubPage.class);
19 | private static final PageUtils PAGE_UTILS = new PageUtils();
20 | protected S a;
21 | protected Page parent = null;
22 |
23 | public final void setParent(Page parent) {
24 | this.parent = parent;
25 | }
26 |
27 | public final Page getParent() {
28 | return this.parent;
29 | }
30 |
31 | public final boolean hasParent() {
32 | return this.parent != null;
33 | }
34 |
35 | public final S getActions() {
36 | return a;
37 | }
38 |
39 | public final void setActions(SeleniumActions actions) {
40 | this.a = (S) actions;
41 | }
42 |
43 | public void pageLoadHook() {
44 | PAGE_UTILS.defaultPageLoadHook(this, a, getPageReadyTimeout());
45 | }
46 |
47 | public TimeoutType getPageReadyTimeout() {
48 | return TimeoutType.PAGE_READY_TIMEOUT;
49 | }
50 |
51 | @Nullable
52 | public By getPageIdentifier() {
53 | return null;
54 | }
55 |
56 | @Nullable
57 | public By getPageContainer() {
58 | return null;
59 | }
60 |
61 | public final void initSubPages() {
62 | PAGE_UTILS.initSubPages(this, a);
63 | }
64 |
65 | @Override
66 | public final void refreshElements() {
67 | PageFactory.initElements(getActions().getBrowser().getWebDriver(), this);
68 | initSubPages();
69 | pageLoadHook();
70 | }
71 |
72 | @Override
73 | public final void refreshPage() {
74 | getActions().getBrowser().refreshPage();
75 | refreshElements();
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/pages/BaseTopLevelPage.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.pages;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.actions.SeleniumActions;
4 | import com.jivesoftware.selenium.pagefactory.framework.browser.web.WebBrowser;
5 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutType;
6 | import com.jivesoftware.selenium.pagefactory.framework.exception.InvalidPageUrlException;
7 | import org.openqa.selenium.By;
8 | import org.openqa.selenium.support.PageFactory;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | import javax.annotation.Nonnull;
13 | import java.net.URI;
14 | import java.util.Optional;
15 | import java.util.regex.Matcher;
16 | import java.util.regex.Pattern;
17 |
18 | /**
19 | * Base abstract class for a TopLevelPage. Implements the default pageLoadHook that waits for the page identifier to be present.
20 | * Subclasses should call super.pageLoadHook() if they want to wait on the page identifier.
21 | */
22 | public class BaseTopLevelPage implements TopLevelPage {
23 | @SuppressWarnings("unused")
24 | private static Logger logger = LoggerFactory.getLogger(BaseTopLevelPage.class);
25 |
26 | private static final PageUtils PAGE_UTILS = new PageUtils();
27 |
28 | private long pageLoadTime;
29 |
30 | protected S a;
31 |
32 | public final S getActions() {
33 | return a;
34 | }
35 |
36 | public final void setActions(SeleniumActions actions) {
37 | this.a = (S) actions;
38 | }
39 |
40 | @Nonnull
41 | @Override
42 | public String getWebPagePath() {
43 | Optional optionalPathFromAnnotation = PAGE_UTILS.getWebPagePathForClass(getClass());
44 | if (optionalPathFromAnnotation.isPresent()) {
45 | return optionalPathFromAnnotation.get();
46 | }
47 | return "/";
48 | }
49 |
50 | @Override
51 | public void pageLoadHook() {
52 | if (pageLoadTime == 0) {
53 | pageLoadTime = System.currentTimeMillis();
54 | }
55 |
56 | // First do the default load hook, which verifies an element is present
57 | PAGE_UTILS.defaultPageLoadHook(this, a, getPageReadyTimeout());
58 |
59 | // Next, verify that the current URL matches the value annotated with @WebPagePath
60 | verifyCurrentURL();
61 | }
62 |
63 | @Override
64 | public TimeoutType getPageReadyTimeout() {
65 | return TimeoutType.PAGE_READY_TIMEOUT;
66 | }
67 |
68 | /**
69 | * Verify that the current URL the browser is pointing to matches the path given by the @WebPagePath annotation.
70 | *
71 | * For example, if the current URL is "http://example.com/foo/bar" and we specify @WebPagePath(path = "/bar") then this would be a match, because we only
72 | * require the URL to end with the given path. (Since we can't know the root context of the server).
73 | *
74 | * If the current URL is "http:/example.com/foo/1234" and we specify @WebPagePath(isRegex = true, path = "/foo/\\d+"), then this would match as a regex.
75 | */
76 | public void verifyCurrentURL() {
77 | WebPagePath webPagePath = getClass().getAnnotation(WebPagePath.class);
78 |
79 | // If the @WebPagePath annotation isn't present, or browser isn't a WebBrowser, then return.
80 | if (webPagePath == null || !(a.getBrowser() instanceof WebBrowser)) {
81 | return;
82 | }
83 |
84 | String expectedPath = webPagePath.path();
85 | boolean regex = webPagePath.isRegex();
86 |
87 | String currentURL = a.getCurrentURL();
88 |
89 | // Not sure when a WebDriver returns null for current URL, but just don't validate in this case
90 | if (currentURL == null) {
91 | return;
92 | }
93 |
94 | URI currentURI = URI.create(currentURL);
95 | String currentPath = currentURI.getPath();
96 |
97 | // Remove trailing slashes
98 | if (currentPath.endsWith("/")) {
99 | currentPath = currentPath.substring(0, currentPath.length() - 1);
100 | }
101 | if (expectedPath.endsWith("/")) {
102 | expectedPath = expectedPath.substring(0, expectedPath.length() - 1);
103 | }
104 |
105 | if (regex) {
106 | Pattern pattern = Pattern.compile(expectedPath);
107 | Matcher m = pattern.matcher(currentPath);
108 | if (!m.find() || m.regionEnd() != currentPath.length()) {
109 | throw new InvalidPageUrlException(String.format("The current path of the web browser is %s, but expected the path to end with an expression " +
110 | "matching the regex '%s'",
111 | currentPath, expectedPath));
112 | }
113 |
114 | logger.info("SUCCESS - the current path {} matches the regex '{}'", currentPath, expectedPath);
115 |
116 | } else {
117 | // The current path should end with the expected path --- we don't know what the Root context of the server is.
118 | if (!currentPath.endsWith(expectedPath)) {
119 | throw new InvalidPageUrlException(String.format("The current path of the web browser is %s, but expected the path to end with '%s'",
120 | currentPath, expectedPath));
121 | }
122 |
123 | logger.info("SUCCESS - the current path {} matches the required path '{}'", currentPath, expectedPath);
124 | }
125 | }
126 |
127 |
128 | @Override
129 | public By getPageIdentifier() {
130 | return null;
131 | }
132 |
133 | public final void initSubPages() {
134 | PAGE_UTILS.initSubPages(this, a);
135 | }
136 |
137 | @Override
138 | public final void refreshElements() {
139 | PageFactory.initElements(getActions().getBrowser().getWebDriver(), this);
140 | initSubPages();
141 | pageLoadHook();
142 | }
143 |
144 | @Override
145 | public void refreshPage() {
146 | getActions().getBrowser().refreshPage();
147 | refreshElements();
148 | }
149 |
150 | @Override
151 | public void leavePageHook() {
152 |
153 | }
154 |
155 | @Override
156 | public long getPageLoadTime() {
157 | return pageLoadTime;
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/pages/Page.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.pages;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.actions.SeleniumActions;
4 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutType;
5 | import org.openqa.selenium.By;
6 |
7 | import javax.annotation.Nullable;
8 |
9 | public interface Page{
10 |
11 | /**
12 | * Get the SeleniumActions for the current page and browser, for how to interact with the page using Selenium.
13 | */
14 | SeleniumActions getActions();
15 |
16 | /**
17 | * Set the selenium actions.
18 | */
19 | void setActions(SeleniumActions actions);
20 |
21 | /**
22 | * Override this to have a page do something different when a page is loaded.
23 | * Make sure to call super.pageLoadHook(), since the BasicPage class defines the check that the page identifier is present.
24 | */
25 | void pageLoadHook();
26 |
27 | TimeoutType getPageReadyTimeout();
28 |
29 | /**
30 | * A Selenium Locator that uniquely identifies a page as being successfully loaded.
31 | * Return null to not verify any element is present on page load.
32 | */
33 | @Nullable
34 | By getPageIdentifier();
35 |
36 | /**
37 | * How to initialize sub-page fields defined with the @SubPage annotation
38 | */
39 | void initSubPages();
40 |
41 | /**
42 | * Call this if a Page has been refreshed by javascript, so it has stale WebElement member variables.
43 | * This is useful when a method of a Page class performs actions requiring multiple refreshes.
44 | * In other situations, you can just use Browser#refreshPage() to get an entirely new Page instance.
45 | */
46 | void refreshElements();
47 |
48 | /**
49 | * Call this to do a full page refresh with the browser, and refresh the web elements as well.
50 | */
51 | void refreshPage();
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/pages/PageUtils.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.pages;
2 |
3 | import com.google.common.base.Preconditions;
4 | import com.google.common.collect.Lists;
5 | import com.jivesoftware.selenium.pagefactory.framework.actions.SeleniumActions;
6 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutType;
7 | import org.openqa.selenium.By;
8 | import org.openqa.selenium.WebDriver;
9 | import org.openqa.selenium.support.PageFactory;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import java.lang.reflect.Field;
14 | import java.net.URI;
15 | import java.util.List;
16 | import java.util.Optional;
17 |
18 | /**
19 | * Created by charles.capps on 7/29/14.
20 | *
21 | * Helpers for interacting with Pages and TopLevelPages
22 | */
23 | public class PageUtils {
24 | private static final Logger logger = LoggerFactory.getLogger(PageUtils.class);
25 |
26 | /**
27 | * Return an Optional<String> representing the path to a web page for a TopLevelPage class.
28 | * The path is extracted using reflection from the {@link WebPagePath} annotation, if present.
29 | *
30 | * @param pageClass
31 | * @return - the Optional<String> that is present with a value if the given Page class was annotated with
32 | * {@link com.jivesoftware.selenium.pagefactory.framework.pages.WebPagePath}
33 | */
34 | public Optional getWebPagePathForClass(Class extends TopLevelPage> pageClass) {
35 | WebPagePath annotation = pageClass.getAnnotation(WebPagePath.class);
36 | if (annotation == null) {
37 | return Optional.empty();
38 | }
39 | return Optional.ofNullable(annotation.path());
40 | }
41 |
42 | /**
43 | * Default implementation of pageLoadHook().
44 | *
45 | * Just verify the page identifier Locator is present on the DOM.
46 | *
47 | * @param page
48 | * @param a
49 | */
50 | public void defaultPageLoadHook(Page page, SeleniumActions a) {
51 | By pageIdentifier = page.getPageIdentifier();
52 | if (pageIdentifier != null) {
53 | a.verifyElementPresented(pageIdentifier, TimeoutType.PAGE_LOAD_TIMEOUT);
54 | }
55 | }
56 |
57 | /**
58 | * Overloaded default implementation of pageLoadHook().
59 | *
60 | * Just verify the page identifier Locator is present on the DOM.
61 | *
62 | * @param page
63 | * @param a
64 | * @param timeout
65 | */
66 | public void defaultPageLoadHook(Page page, SeleniumActions a, TimeoutType timeout) {
67 | By pageIdentifier = page.getPageIdentifier();
68 | if (pageIdentifier != null) {
69 | a.verifyElementPresented(pageIdentifier, timeout);
70 | }
71 | }
72 |
73 | /**
74 | * Use reflection to recursively get all fields annotated with {@link SubPageField} on a given class.
75 | * @param type
76 | * @return - List of Fields that are annotated with {@link com.jivesoftware.selenium.pagefactory.framework.pages.SubPageField}
77 | * and are of type {@link com.jivesoftware.selenium.pagefactory.framework.pages.SubPage},
78 | * recursively including fields from super classes.
79 | */
80 | public static List getAllSubpageFields(Class> type) {
81 | List subpageFields = Lists.newArrayList();
82 | for (Field field : type.getDeclaredFields()) {
83 | if (field.getAnnotation(SubPageField.class) != null) {
84 | if (SubPage.class.isAssignableFrom(field.getType())) {
85 | subpageFields.add(field);
86 | } else {
87 | logger.warn("Class {} has a field annotated with @SubPageField that isn't a SubPage type", type.getSimpleName());
88 | }
89 | }
90 | }
91 |
92 | if (type.getSuperclass() != null) {
93 | subpageFields.addAll(getAllSubpageFields(type.getSuperclass()));
94 | }
95 |
96 | return subpageFields;
97 | }
98 |
99 | public void initSubPages(Page page, SeleniumActions a) {
100 | Preconditions.checkNotNull(a);
101 | Preconditions.checkNotNull(page);
102 | List fields = getAllSubpageFields(page.getClass());
103 | for (Field field : fields) {
104 | Class type = field.getType();
105 | if (!SubPage.class.isAssignableFrom(type)) {
106 | logger.warn("Invalid @SubPageField in class '%s'. Must be a subclass of SubPage.");
107 | continue;
108 | }
109 |
110 | SubPage subPage = PageFactory.initElements(a.getBrowser().getWebDriver(), (Class extends SubPage>) field.getType());
111 | subPage.setActions(a);
112 | subPage.setParent(page);
113 | subPage.pageLoadHook();
114 | subPage.initSubPages();
115 |
116 | //Set the subpage field
117 | try {
118 | field.setAccessible(true);
119 | field.set(page, subPage);
120 | } catch (IllegalAccessException ex) {
121 | logger.error("Error instantiating SubPage field: " + field, ex);
122 | throw new RuntimeException(ex);
123 | }
124 | }
125 | }
126 |
127 | public void initSubPagesWithoutPageLoadHooks(Page page, SeleniumActions a) {
128 | Preconditions.checkNotNull(a);
129 | Preconditions.checkNotNull(page);
130 | List fields = getAllSubpageFields(page.getClass());
131 | for (Field field : fields) {
132 | Class type = field.getType();
133 | if (!SubPage.class.isAssignableFrom(type)) {
134 | logger.warn("Invalid @SubPageField in class '%s'. Must be a subclass of SubPage.");
135 | continue;
136 | }
137 |
138 | SubPage subPage = PageFactory.initElements(a.getBrowser().getWebDriver(), (Class extends SubPage>) field.getType());
139 | subPage.setActions(a);
140 | subPage.setParent(page);
141 | initSubPagesWithoutPageLoadHooks(subPage, a);
142 |
143 | //Set the subpage field
144 | try {
145 | field.setAccessible(true);
146 | field.set(page, subPage);
147 | } catch (IllegalAccessException ex) {
148 | logger.error("Error instantiating SubPage field: " + field, ex);
149 | throw new RuntimeException(ex);
150 | }
151 | }
152 | }
153 |
154 | public void runPageLoadHooksForSubPages(Page page, SeleniumActions a) {
155 | Preconditions.checkNotNull(a);
156 | Preconditions.checkNotNull(page);
157 | List fields = getAllSubpageFields(page.getClass());
158 | for (Field field : fields) {
159 | Class type = field.getType();
160 | if (!SubPage.class.isAssignableFrom(type)) {
161 | logger.warn("Invalid @SubPageField in class '%s'. Must be a subclass of SubPage.");
162 | continue;
163 | }
164 |
165 | //Get the subpage field
166 | SubPage subPage;
167 | try {
168 | field.setAccessible(true);
169 | subPage = (SubPage) field.get(page);
170 | } catch (IllegalAccessException ex) {
171 | logger.error("Error instantiating SubPage field: " + field, ex);
172 | throw new RuntimeException(ex);
173 | }
174 | if (subPage != null) {
175 | subPage.pageLoadHook();
176 | runPageLoadHooksForSubPages(subPage, a);
177 | }
178 | }
179 | }
180 |
181 | public T loadPageFromURL(URI absoluteURL, Class pageClass, WebDriver driver, SeleniumActions actions) {
182 | Preconditions.checkNotNull(absoluteURL, "Error: URI provided cannot be null in PageUtils#loadPageFromURL");
183 | Preconditions.checkNotNull(pageClass);
184 | Preconditions.checkNotNull(driver);
185 | Preconditions.checkNotNull(actions);
186 | Preconditions.checkArgument(absoluteURL.isAbsolute(), "Error: must provide an absolute URL to PageUtils#loadPageFromURL");
187 | driver.get(absoluteURL.toString());
188 | return loadCurrentPage(pageClass, driver, actions);
189 | }
190 |
191 | public T loadCurrentPage(Class pageClass, WebDriver driver, SeleniumActions actions) {
192 | T page = PageFactory.initElements(driver, pageClass);
193 | page.setActions(actions);
194 | page.initSubPages();
195 | page.pageLoadHook();
196 | return page;
197 | }
198 |
199 | public T loadCurrentPageWithoutPageLoadHook(Class pageClass, WebDriver driver, SeleniumActions actions) {
200 | T page = PageFactory.initElements(driver, pageClass);
201 | page.setActions(actions);
202 | initSubPagesWithoutPageLoadHooks(page, actions);
203 | return page;
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/pages/SubPage.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.pages;
2 |
3 | import org.openqa.selenium.By;
4 |
5 | /**
6 | * Created by charles.capps on 7/29/14.
7 | */
8 | public interface SubPage extends Page {
9 | /**
10 | * Set parent page for the subpages.
11 | */
12 | void setParent(Page parent);
13 |
14 | /**
15 | * get parent page from the subpages.
16 | */
17 | Page getParent();
18 |
19 | boolean hasParent();
20 |
21 | /**
22 | * A Selenium locator that returns page container locator; useful for nav bars, side bars,
23 | * inbox message items.
24 | */
25 | By getPageContainer();
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/pages/SubPageField.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.pages;
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 | /**
9 | * Marker interface indicating that a field that extends {@link SubPage}
10 | * should be loaded when the page is initialized.
11 | */
12 | @Retention(RetentionPolicy.RUNTIME)
13 | @Target(ElementType.FIELD)
14 | public @interface SubPageField {
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/pages/TopLevelPage.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.pages;
2 |
3 | import javax.annotation.Nonnull;
4 |
5 | /**
6 | * Represents a Page that is a top-level web page.
7 | */
8 | public interface TopLevelPage extends Page {
9 |
10 | @Nonnull
11 | String getWebPagePath();
12 |
13 | void leavePageHook();
14 |
15 | long getPageLoadTime();
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/pages/WebPagePath.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.pages;
2 |
3 | import javax.annotation.Nonnull;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Created by charles.capps on 7/29/14.
11 | *
12 | * An annotation on a TopLevelPage class indicating the path part of the URI to the web page resource.
13 | *
14 | * e.g. "/social-business-software/social-community-software/" would be the path for
15 | * http://www.jivesoftware.com/social-business-software/social-community-software/
16 | */
17 | @Retention(RetentionPolicy.RUNTIME)
18 | @Target(ElementType.TYPE)
19 | public @interface WebPagePath {
20 |
21 | @Nonnull String path();
22 |
23 | boolean isRegex() default false;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/jivesoftware/selenium/pagefactory/framework/webservice/EndpointBuilder.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework.webservice;
2 |
3 | public class EndpointBuilder {
4 | public static String uri(String host, String root, String relativePath) {
5 | String absolutePath = buildAbsolutePath(root, relativePath);
6 | return buildUri(host, absolutePath);
7 | }
8 |
9 | private static String buildUri(String host, String absolutePath) {
10 | while (host.endsWith("/") && host.length() > 1) {
11 | host = host.substring(0, host.length() - 1);
12 | }
13 | return host + absolutePath;
14 | }
15 |
16 | private static String buildAbsolutePath(String root, String relativePath) {
17 | String separator = root.endsWith("/") ? "" : "/";
18 | return root + separator + relativePath;
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/test/java/com/jivesoftware/selenium/pagefactory/framework/CreateWebBrowserTests.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework;
2 |
3 | import com.jivesoftware.selenium.pagefactory.framework.browser.LocalBrowserBuilder;
4 | import com.jivesoftware.selenium.pagefactory.framework.browser.web.WebBrowser;
5 | import com.jivesoftware.selenium.pagefactory.framework.browser.web.WebBrowserType;
6 | import com.jivesoftware.selenium.pagefactory.framework.config.TimeoutType;
7 | import com.jivesoftware.selenium.pagefactory.framework.exception.JiveWebDriverException;
8 | import org.openqa.selenium.By;
9 | import org.testng.annotations.Test;
10 |
11 | /**
12 | * Created by charles.capps on 8/21/14.
13 | *
14 | * Basic Functional tests for creating different web browsers.
15 | */
16 | public class CreateWebBrowserTests {
17 |
18 | @Test
19 | public void openGoogleChrome() throws Exception {
20 | WebBrowser chromeBrowser = createMinimalChrome();
21 | chromeBrowser.openPageByURL("http://google.com");
22 |
23 | chromeBrowser.getActions().verifyElementVisible(
24 | By.cssSelector("form[action='/search']"), // The google search form
25 | TimeoutType.DEFAULT);
26 |
27 | chromeBrowser.quit();
28 | }
29 |
30 |
31 | private WebBrowser createMinimalChrome() throws JiveWebDriverException {
32 | return LocalBrowserBuilder.getBuilder(WebBrowserType.CHROME, "http://google.com")
33 | .withWebDriverPath(TestSystemProps.WEB_DRIVER_PATH)
34 | .build();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/java/com/jivesoftware/selenium/pagefactory/framework/TestSystemProps.java:
--------------------------------------------------------------------------------
1 | package com.jivesoftware.selenium.pagefactory.framework;
2 |
3 | /**
4 | * Created by charles.capps on 8/21/14.
5 | */
6 | public class TestSystemProps {
7 | public static final String WEB_DRIVER_PATH = System.getProperty("tests.webDriverPath");
8 | }
9 |
--------------------------------------------------------------------------------
/src/test/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/tools/ci/DEFS:
--------------------------------------------------------------------------------
1 | WORKSPACE=${WORKSPACE:-`pwd`}
2 | GIT=git
3 | if [ -f "/opt/tools/maven/apache-maven-3.0.4/bin/mvn" ]; then
4 | MVN="/opt/tools/maven/apache-maven-3.0.4/bin/mvn -U --batch-mode --define maven.repo.local=$WORKSPACE/.repository"
5 | else
6 | MVN="mvn"
7 | fi
8 |
9 | echo "MVN=$MVN"
10 |
11 | PYTHON=/usr/bin/python2.6
12 | if [ -d "/opt/tools/java/jdk1.8.0_31" ]; then
13 | export JAVA_HOME="/opt/tools/java/jdk1.8.0_31"
14 | fi
15 |
16 | if [ ! -f $PYTHON ];
17 | then
18 | PYTHON=python
19 |
20 | # if 'python2.6' dones't exist, make sure python is 2.6 or later
21 | PYTHON_OK=`$PYTHON -c 'import sys; print (sys.version_info >= (2, 6) and "1" or "0")'`
22 | if [ "$PYTHON_OK" = '0' ]; then
23 | echo "Python version too old"
24 | exit 1
25 | fi
26 | fi
--------------------------------------------------------------------------------
/tools/ci/commit/commit:
--------------------------------------------------------------------------------
1 | . tools/ci/DEFS
2 |
3 | # First deploy the SNAPSHOT version
4 | $MVN deploy -Prelease -DsnapshotRepoId=${SNAPSHOT_REPO_ID} -DsnapshotRepoUrl=${SNAPSHOT_REPO_URL} -DreleaseRepoId=${RELEASE_REPO_ID} -DreleaseRepoUrl=${RELEASE_REPO_URL} -DskipTests
5 |
6 | # Next deploy the RELEASE version
7 | # 2.0.4-6-g012333 : version number
8 | version=$(./tools/ci/commit/j-version)
9 | echo "Deploying version: $version"
10 |
11 | $MVN versions:set -DnewVersion=$version
12 | $MVN deploy -Prelease -DsnapshotRepoId=${SNAPSHOT_REPO_ID} -DsnapshotRepoUrl=${SNAPSHOT_REPO_URL} -DreleaseRepoId=${RELEASE_REPO_ID} -DreleaseRepoUrl=${RELEASE_REPO_URL} -DskipTests
13 |
--------------------------------------------------------------------------------
/tools/ci/commit/j-version:
--------------------------------------------------------------------------------
1 | #version based on commit count since last tag
2 | last_tag=$(git rev-list --tags --max-count=1)
3 | base_version=$(git describe --tags $last_tag)
4 |
5 | artifactPattern="jive-selenium-pages-framework<\/artifactId>"
6 |
7 | # First get the 2 lines surrounding the main tag
8 | # Next get the line with the
9 | # Next use sed to get everything before "SNAPSHOT"
10 | # Example result: 8.0.0.0-8c6
11 | pom_version=$(grep -2 ${artifactPattern} pom.xml | \
12 | grep -Eo "[^<>\s]*-SNAPSHOT<\/version>" | \
13 | sed -E "s/([^<>\s]*)-SNAPSHOT<\/version>/\1/")
14 |
15 | last_commitish=$(git rev-list --max-count=1 $base_version --)
16 | commit_count=$(git rev-list $last_commitish..HEAD | wc -w)
17 | head_short_sha=$(git rev-parse --short HEAD)
18 |
19 | printf "%s-%s-g%s\n" $pom_version $commit_count $head_short_sha
20 |
--------------------------------------------------------------------------------