Selenium WebDriver 3x (Java)
Selenium WebDriver 3x (Java)
Functional UI Testing
with Selenium Web Driver
3.0
www.luxoft-training.pro
Introduction
• Let’s introduce ourselves
• Name & Position - Marian Constantin, Team Lead Luxoft
• Automation Testing experience
• Selenium experience
www.luxoft-training.pro
Agenda
• Introduction to Selenium
• WebDriver
• WebElement
• Locators
• Waits
• Design Patterns
• Advanced Selenium
• Grid
www.luxoft-training.pro
Resources
• IntelliJ IDEA (Community Edition)
• Git
www.luxoft-training.pro
Environment Setup
www.luxoft-training.pro
SELENIUM ECOSYSTEM
www.luxoft-training.pro
What is Selenium?
• Selenium controls web browsers
• a toolset for web browser automation to remotely control browser instances
• emulates a user’s interaction with the browser
• API
• This is the set of commands you use to manipulate WebDriver.
• https://www.selenium.dev/selenium/docs/api/java/index.html
• Library
• A code module which contains the APIs and the code necessary to
implement them.
• Libraries are specific to each language binding, eg .jar files for Java, .dll files
for .NET, etc.
Selenium WebDriver - language bindings && implementations of the individual browser controlling
code
www.luxoft-training.pro
Terminology II
• Driver
• Responsible for controlling the actual browser
• Usually created by the browser vendors themselves
• Executable modules that run on the system with the browser itself, not on the
system executing the test suite
• Framework
• An additional library used as a support for WebDriver suites
• May be test frameworks (JUnit, NUnit, pytest), even supporting natural language
features (Cucumber, Robotium)
• May be written and used for manipulating or configuring the SUT, data creation, test
oracles, etc.
www.luxoft-training.pro
SELENIUM: ECOSYSTEM
• Selenium WebDriver
• drives a browser natively, as a user would, either locally or on a
remote machine using the Selenium server
• Accepts commands using Client API and send them to browser
launched by driver class
• Listen commands from Selenium API → converts commands to
browser native API → send native commands output back
• Collection of language-specific client libs
https://selenium.dev/documentation/en/
www.luxoft-training.pro
SELENIUM: ECOSYSTEM
• Selenium Server
• Allows test run on remote machine browser instances
www.luxoft-training.pro
SELENIUM: ECOSYSTEM
• Selenium IDE (not supported)
• Record-playback Firefox add-on
www.luxoft-training.pro
SELENIUM: WebDriver - direct communication
www.luxoft-training.pro
SELENIUM: Remote WebDriver
www.luxoft-training.pro
SELENIUM: Selenium Server/Grid
www.luxoft-training.pro
SELENIUM: Framework
www.luxoft-training.pro
SELENIUM: 2.0 → 3.0
www.luxoft-training.pro
SELENIUM WEBDRIVER
www.luxoft-training.pro
SELENIUM: W3C
https://www.w3.org/TR/webdriver1/
www.luxoft-training.pro
WEBDRIVER: W3C SPEC
• Protocol
• Remote end – HTTP server
www.luxoft-training.pro
WEBDRIVER: W3C SPEC
• Nodes
• Local end – client side implementation for WebDriver protocol in form
of language-specific libraries (Java, C#, Ruby etc...)
www.luxoft-training.pro
WEBDRIVER: Selenium WebDriver
• Drives a browser natively, as a user would, either locally or on a
remote machine using the Selenium server
• Accepts commands using Client API and send them to browser
launched by driver class
• Listen commands from Selenium API → converts commands to
browser native API → send native commands output back
• Collection of language-specific client libs
https://selenium.dev/documentation/en/
www.luxoft-training.pro
WEBDRIVER: Requirements
www.luxoft-training.pro
WEBDRIVER: W3C SPEC - errors
www.luxoft-training.pro
WEBDRIVER IMPLEMENTATIONS
www.luxoft-training.pro
WD IMPLEMENTATIONS: FIREFOX DRIVER
• https://github.com/mozilla/geckodriver
• webdriver.gecko.driver property
• FirefoxOptions fo = new FirefoxOptions()
• fo.setHeadlessMode(boolean) – CI
• fo.setProfile(fp)
• FirefoxProfile fp = new FirefoxProfile
• fp.addExtension(File extensionXpiFile)
• fp.setPreferences(String key, String value)
www.luxoft-training.pro
SELENIUM: FIREFOX DRIVER
Examples:
FirefoxProfile profile = new FirefoxProfile();
profile.addExtension( new
File("./src/test/resources/extensions/xpath_finder.xpi"));
FirefoxOptions firefoxOptions = new FirefoxOptions();
firefoxOptions.setHeadless(true);
firefoxOptions.setProfile(profile);
driver = new FirefoxDriver(firefoxOptions);
www.luxoft-training.pro
WD IMPLEMENTATIONS: CHROME DRIVER
• http://chromedriver.chromium.org/
• webdriver.chrome.driver property
• ChromeOptions co = new ChromeOptions()
• co.setHeadlessMode(boolean)
• co.addExtension(File extensionCrxFile)
www.luxoft-training.pro
SELENIUM: CHROME DRIVER
Examples:
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addExtensions(new File("/path/to/extension.crx"));
chromeOptions.setHeadless(true);
driver = new ChromeDriver(chromeOptions);
www.luxoft-training.pro
WD IMPLEMENTATIONS: CHROME MOBILE EMULATION
• setExperimentalOption("mobileEmulation",
HashMap<String, Object> me)
www.luxoft-training.pro
SELENIUM: EXPERIMENTAL MODE
Examples:
Map<String, Object> deviceMetrics = new HashMap<>();
deviceMetrics.put("width", 430);
deviceMetrics.put("height", 853);
deviceMetrics.put("pixelRatio", 2.0);
Map<String, Object> mobileEmulation = new HashMap<>();
mobileEmulation.put("deviceMetrics", deviceMetrics);
mobileEmulation.put("userAgent", "Mozilla/5.0 (Linux; Android 8.0.0;"
+ "Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36
(KHTML, like Gecko) "+"Chrome/67.0.3396.99 Mobile Safari/537.36");
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.setExperimentalOption("mobileEmulation",
mobileEmulation);
driver = new ChromeDriver(chromeOptions);
www.luxoft-training.pro
WD IMPLEMENTATIONS: OTHERS
• https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver
• https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver
• Safari built-in
www.luxoft-training.pro
WD FEATURES: NAVIGATION
• Navigation
• get("https://selenium.dev")
• back()
• forward()
• refresh()
www.luxoft-training.pro
WD FEATURES: TAKING SCREENSHOTS
Examples:
driver = new ChromeDriver();
driver.get("http://www.google.com");
File scrFile =
((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new
File("./target/googleShot.png"));
www.luxoft-training.pro
WD FEATURES: SWITCHING TABS
• String webDriver.getWindowHandle() – current tab
• webDriver.switchTo().window(String) – switch
www.luxoft-training.pro
WD FEATURES: Tabs, Windows, Frames
Examples:
String firstTab = driver.getWindowHandle();
System.out.println("First tab is: " + firstTab);
WebElement button = driver.findElement(By.tagName("button"));
button.click();
String secondTab = driver.getWindowHandle();
System.out.println("Second tab is: " + secondTab);
System.out.println("Number of tabs "+
driver.getWindowHandles().size());
driver.switchTo().window(firstTab);
www.luxoft-training.pro
WD FEATURES: ALERTS
• module-selenium.webdriver.common.alert
• accept() = OK
• dismiss() = Cancel
• text()
• sendKeys()
• driver.switchTo().alert();
www.luxoft-training.pro
SELENIUM: PROMPTS
Examples:
www.luxoft-training.pro
WD FEATURES: JAVASCRIPT CODE EXECUTION
Common usages
• get elements text or attribute
• find an element
• do some operation on an element, like click()
• change attributes of an element
• scroll to an element or location on a web page
• wait until the page is loaded
www.luxoft-training.pro
WD FEATURES: JAVASCRIPT CODE EXECUTION
www.luxoft-training.pro
SELENIUM: JAVASCRIPT
Examples:
WebDriver driver = new ChromeDriver();
driver.get("http://www.google.com");
JavascriptExecutor js = (JavascriptExecutor) driver;
String title = (String) js.executeScript("return
document.title");
assertEquals("Google", title);
www.luxoft-training.pro
WD FEATURES: COOKIES
• For example to skip sign in actions
• webDriver.manage().
• Set<Cookie> getCookies()
• Cookie getCookieNamed(String)
• addCookie(Cookie)
• deleteCookie(Cookie)
• deleteAllCookies()
www.luxoft-training.pro
SELENIUM: COOKIES
Examples:
WebDriver wd = new FirefoxDriver();
Cookie cookie = new
Cookie("SeleniumIntroductionCookie","SICookieValue");
wd.manage().addCookie(cookie);
System.out.println(wd.manage().getCookieNamed("SeleniumIntroductionCoo
kie"));
wd.manage().deleteCookie(cookie);
MatcherAssert.assertThat(
wd.manage().getCookieNamed("SeleniumIntroductionCookie"),
is(nullValue()));
www.luxoft-training.pro
WEB ELEMENT
www.luxoft-training.pro
SELENIUM: WEBELEMENTS
• Common elements
• links
• textboxes
• buttons
• radio buttons
• checkboxes
• body
• labels
• With Selenium we are locating elements and manipulating them
www.luxoft-training.pro
SELENIUM: ELEMENTS INSPECTION
• Document Object Model tree
• $("css_selector") or $x("xpath_selector")
www.luxoft-training.pro
SELENIUM: findElement(s)
• By instance as argument – locating mechanism
• findElement
• Return WebElement instance representing actual HTML element
• First element satisfying By criteria
• NoSuchElementException (runtime) found no elements
• findElements
• Return list of WebElements
• Empty list when no elements found
www.luxoft-training.pro
SELENIUM: findElement(s)
Syntax:
public WebElement findElement(By locator)
www.luxoft-training.pro
SELENIUM: BY - locator strategies
driver.findElement(By.id("search_query_top")).sendKeys("dress");
driver.findElement(By.partialLinkText("Contact")).click();
driver.findElements(By.xpath("//input[@name='id_gender']"))
.get(1).click();
www.luxoft-training.pro
SELENIUM: BY - XPath
Syntax:
By.xpath xpathSelector
Examples:
"/html/body/div/div/form/input" – absolute path
"//input" – relative path
"//input[2]" – specific element
"//input[@type='submit'][@value='Login']" - attribute
"//input[contains(@id,'userName')]" – attribute value
"//*[@class='price']" – when node type is unknown
"//td[contains(text(),'Item 1')]" – by element text
www.luxoft-training.pro
SELENIUM: BY - CSS
Syntax:
By.cssSelector cssSelector
Examples:
"html > body > div > div > form" – parent-to-child
"input#username" – using id
"input.login" – using class
"input[type='submit']" - attribute
"input[id*='userName']" – attribute value substring
www.luxoft-training.pro
ELEMENTS: PROPERTIES & ATTRIBUTES
• String getAttribute()
• name, id, class, value…
• String getText()
• String getCssValue(String )
• height, width, padding…
www.luxoft-training.pro
ELEMENTS: PROPERTIES & ATTRIBUTES
• Point getLocation()
• Relative element position after page rendering
• Dimension getSize()
• Width & height
• String getTagName()
www.luxoft-training.pro
SELENIUM: PROPERTIES & ATTRIBUTES
Examples:
WebElement loginButton =
webDriver.findElement(By.id("login"));
String btnAlign = loginButton.getAttribute("align");
Assertions.assertTrue(loginButton.getText().contains("Login");
String btnWidth = loginButton.getCssValue("width");
Point btnLocation = loginButton.getLocation();
Dimension btnSize = loginButton.getSize();
Assertions.assertEquals("button",loginButton.getTagName());
www.luxoft-training.pro
ELEMENTS: ACTIONS
• sendKeys(CharSequence)
• Keys enum – Enter, Ctrl, Esc
• Keys.chord(Keys.SHIFT, "text")->TEXT
• clear()
• submit()
www.luxoft-training.pro
ELEMENTS: STATE
• isDisplayed()
• isEnabled()
• isSelected()
www.luxoft-training.pro
SELENIUM: STATE & ACTIONS
Examples:
WebElement checkBox = driver.findElement(By.name("option_box"));
if (checkBox.isEnabled()) {
if (!checkBox.isSelected()) {
checkBox.click();
}
} else {
fail("Option Checkbox is disabled!!");
}
www.luxoft-training.pro
ELEMENTS: SELECT
• Dropdown list wrapper
• new Select(driver.findElement(By.name("make")))
• selectByVisibleText(String)
• (de)selectByValue(String)
• (de)selectByIndex(int)
• List<String> getOptions()
• boolean isMultiple()
www.luxoft-training.pro
SELENIUM: SELECT
Examples:
Select shopLocation = new
Select(driver.findElement(By.className("shop_location")));
boolean isMultiple = shopLocation.isMultiple()
if (isMultiple) {
int listSize = shopLocation.getOptions().size();
}
shopLocation.selectByVisibleText("Poland");
shopLocation.selectByValue("Belarus");
shopLocation.selectByIndex(4);
//if multiple
int selectedLocations = shopLocation.getAllSelectedOptions().size()
www.luxoft-training.pro
WEBDRIVER WAITS
www.luxoft-training.pro
WD WAITS: syn vs. asyn
• the function calls will not return until the command has been
completed in the browser.
• The advanced user interaction APIs, Keyboard and Mouse, are
exceptions as they are explicitly intended as “do what I say”
asynchronous commands.
www.luxoft-training.pro
WD WAITS: IMPLICIT WAIT
• WebDriver polls the DOM for a certain duration when trying to find
any element.
• The default setting is 0, meaning disabled.
• Once set, the implicit wait is set for the life of the session.
www.luxoft-training.pro
WD WAITS: IMPLICIT WAIT
www.luxoft-training.pro
Implicit wait example
Examples:
www.luxoft-training.pro
WD WAITS: EXPLICIT WAIT
www.luxoft-training.pro
Expected Conditions
Common checks are already defined as ExpectedConditions
Examples:
• alert is present
• element exists
• element is visible
• title contains
• title is
• element staleness
• visible text, etc.
www.luxoft-training.pro
SELENIUM: EXPLICIT WAIT
Examples:
WebDriver wd = new FirefoxDriver();
WebElement WebDriverWait(wd, 10).until(
ExpectedCondition<WebElement>d->d.findElement(By.id("search"))
)
www.luxoft-training.pro
WD FEATURES: FLUENT WAIT
• Custom pooling time and exception ignoring capability
new FluentWait<WebDriver>(driver)
.withTimeout(int, TimeUnit)
.pollingEvery(int, TimeUnit)
.withMessage(String)
.ignoring(Throwable, Throwable)
www.luxoft-training.pro
SELENIUM: FLUENT WAIT
Examples:
public static WebElement findElementWithFluentWait(WebDriver wd, By
locator) {
return new FluentWait<>(wd)
.withTimeout(Duration.ofSeconds(60))
.pollingEvery(Duration.ofSeconds(1))
.ignoring(StaleElementReferenceException.class,
NoSuchElementException.class)
.until(webDriver -> webDriver.findElement(locator));
}
www.luxoft-training.pro
WEBDRIVER ADVANCED ELEMENT
INTERACTIONS
www.luxoft-training.pro
ADVANCED INTERACTIONS: ACTION CHAINS
• Mouse-based & keyword-based actions
www.luxoft-training.pro
ADVANCED INTERACTIONS : 3 STEPS
The action creation process:
www.luxoft-training.pro
ADVANCED INTERACTIONS : MOUSE-BASED
• Actions moveByOffset(int xOffset, int yOffset)
• Mouse in (0,0) by default after page load
www.luxoft-training.pro
ADVANCED INTERACTIONS : MOUSE-BASED
• Actions clickAndHold()/ clickAndHold(WebElement
onElement) – for drag-and-drop
www.luxoft-training.pro
ADVANCED INTERACTIONS : MOUSE-BASED
• Actions moveToElement(WebElement onElement)
www.luxoft-training.pro
ADVANCED INTERACTIONS : MOUSE-BASED
• Actions dragAndDropBy(WebElement source, int
xOffset, int yOffset)
www.luxoft-training.pro
ADVANCED INTERACTIONS : KEYBOARD-BASED
• Actions keyDown(Keys key) - press and hold the key
• Shift, Ctrl, Alt; other – IllegalArgumentException
• Actions sendKeys(CharSequence)
www.luxoft-training.pro
SELENIUM: ACTIONS
Examples:
WebDriver wd = new ChromeDriver();
Actions builder = new Actions(wd);
Action complexMove =
builder.moveToElement(wd.findElement(By.id("id1")))
.pause(Duration.ofSeconds(2))
.moveToElement(wd.findElement(By.id("id2")))
.click()
.build();
complexMove.perform();
www.luxoft-training.pro
DESIGN PATTERNS
www.luxoft-training.pro
COMMON DESIGN PATTERNS
● Domain Driven Design: Express your tests in the language of the end-user of
the app.
● PageObjects: A simple abstraction of the UI of your web app.
● LoadableComponent: Modeling PageObjects as components.
● BotStyleTests: Using a command-based approach to automating tests, rather
than the object-based approach that PageObjects encourage
● AcceptanceTests: Use coarse-grained UI tests to help structure development
work.
● RegressionTests: Collect the actions of multiple AcceptanceTests into one
place for ease of maintenance. … read more on Design-Patterns
www.luxoft-training.pro
PAGE OBJECT: MARTIN FOWLER
• https://martinfowler.com/bliki/PageObject.html
• HTML page wrapper with an application-specific API
• Hide details of UI structure from test
• Should allow anything that a human can do ← rule of
• Use inheritance
• Limited or no assertions
• Case study:
• https://github.com/SeleniumHQ/selenium/wiki/PageObjects
www.luxoft-training.pro
PAGE OBJECT
• Main benefit:
• if the UI changes for the page, the tests themselves don’t need to
change, only the code within the page object needs to change.
www.luxoft-training.pro
Advantages of Page Object
● There is a clean separation between test code and page specific
code such as locators (or their use if you’re using a UI Map) and
layout.
● There is a single repository for the services or operations offered by
the page rather than having these services scattered throughout
the tests.
www.luxoft-training.pro
SELENIUM GRID
www.luxoft-training.pro
Selenium Grid
• A smart proxy server that allows tests to route commands to remote
web browser instances.
• Its aim is to provide an easy way to run tests in parallel
• on multiple machines
• with different browser versions
• different browser configurations
• One server acts as the hub that routes JSON formatted test
commands to one or more registered Grid nodes.
• Tests contact the hub to obtain access to remote browser
instances.
www.luxoft-training.pro
•
Purposes and main functionalities
● Central entry point for all tests
● Management and control of the nodes / environment where the
browsers run
● Scaling
● Running tests in parallel
● Cross platform testing
● Load balancing
www.luxoft-training.pro
Components of a Grid
www.luxoft-training.pro
SELENIUM GRID: SELENIUM SERVER
• Download JAR to the remote machine where browsers located
• Start the server:
java -jar selenium-server-standalone-{VERSION}.jar
• Timeout mode:
java -jar selenium-server-standalone-{VERSION}.jar
-timeout=20 -browserTimeout=60
www.luxoft-training.pro
SELENIUM GRID: Remote WebDriver
www.luxoft-training.pro
SELENIUM GRID: SCRIPT CHANGES
www.luxoft-training.pro
Remote for Chrome
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.setCapability("browserVersion", "67");
chromeOptions.setCapability("platformName", "Windows XP");
WebDriver driver = new RemoteWebDriver(new
URL("http://www.example.com"), chromeOptions);
driver.get("http://www.google.com");
driver.quit();
www.luxoft-training.pro
Remote for Firefox
FirefoxOptions firefoxOptions = new FirefoxOptions();
WebDriver driver = new RemoteWebDriver(new
URL("http://www.example.com"), firefoxOptions);
driver.get("http://www.google.com");
driver.quit();
www.luxoft-training.pro
Upload files on Remote
// set up local file detector
driver.setFileDetector(new LocalFileDetector());
// do the upload
driver.get("http://sso.dev.saucelabs.com/test/guinea-file-upload"
);
WebElement upload = driver.findElement(By.id("myfile"));
upload.sendKeys("/Users/sso/the/local/path/to/darkbulb.jpg");
www.luxoft-training.pro
SELENIUM GRID: accessing the Grid web interface
• Web interface
www.luxoft-training.pro
SELENIUM GRID: HUB
• Registering a Node:
java -jar selenium-server-standalone.jar -role node -hub
http://localhost:4444
www.luxoft-training.pro
SELENIUM GRID: NODE
• Node
• Where the browsers live
• Registers itself to the hub and communicates its capabilities
• Receives requests from the hub and executes them
• Registering a Node:
java -jar selenium-server-standalone.jar -role node -hub
http://localhost:4444
www.luxoft-training.pro
SELENIUM GRID: STEPS PERFORMED
• Node:
• Creates new session with desired options
www.luxoft-training.pro
SELENIUM GRID: CONFIGURATION
• Set node supported browsers
• -browser browserName=firefox -browser browserName=chrome
www.luxoft-training.pro
SELENIUM GRID: CONFIGURATION
• Set hub new session timeout
• -newSessionWaitTimeout 120000
www.luxoft-training.pro
GUIDELINES
www.luxoft-training.pro
The DOs..
• Page Object models
• Domain specific language
• Generating application state
• Mock external services
• CI and Improved reporting
• Avoid sharing state
• Test independency
• Consider using a fluent API
• Fresh browser per test
www.luxoft-training.pro
Domain specific language (DSL)
• Readable: Business stakeholders can understand it.
• Writable: Easy to write, avoids unnecessary duplication.
• Extensible: Functionality can (reasonably) be added without
breaking contracts and existing functionality.
• Maintainable: By leaving the implementation details out of test
cases, you are well-insulated against changes to the AUT.
www.luxoft-training.pro
Generating application state
• Selenium should not be used to prepare a test case.
• All repetitive actions and preparations for a test case, should be
done through other methods.
• Eliminating logging in via web browser before every test will
improve both the speed and stability of the test.
• A method should be created to gain access to the AUT*
• e.g. using an API to login and set a cookie.
• Input data should not be created by Selenium
www.luxoft-training.pro •
Avoid sharing state
• Do not share test data.
• Imagine several tests that each query the database for valid orders
before picking one to perform an action on. Should two tests pick
up the same order you are likely to get unexpected behaviour.
• Clean up stale data in the application that might be picked up by
another test
• e.g. invalid order records.
• Create a new WebDriver instance per test.
• This helps ensure test isolation and makes parallelization simpler.
www.luxoft-training.pro
Domain specific language
• Mock external services
• greatly improve the speed and stability of your tests
• CI and Improved reporting
• Test independency
• a test shouldn’t depend of affect another test.
• Consider using a Fluent API
• object-oriented API whose design relies extensively on method
chaining. Its goal is to increase code legibility by creating a DSL
• Fresh browser per test
www.luxoft-training.pro
.. and the DON’Ts!
• CAPTCHA - disable or bypass, don’t try to automate
• Although possible, don’t try to test file downloads
• Don’t try to verify HTTP response codes
• Automating logins for Facebook, Gmail, Tinder, etc. - No!
• Shouldn’t try to order test execution
• Performance testing → jmeter
• Web crawling
www.luxoft-training.pro
REFERENCES
• https://selenium.dev
• https://www.safaribooksonline.com/library/view/selenium-webdriver-3
/9781788999762/
• https://www.safaribooksonline.com/library/view/selenium-testing-tools
/9781784392512/
www.luxoft-training.pro