UI Automation at Scale
Augmented Driver
fernando@split.io
A little bit about me
● Started working @Google in late 2006.
A little bit about me
● Started working @Google in late 2006.
● Selenium/Webdriver started becoming a “thing” sometime in 2007.
A little bit about me
● In 2010 I joined Medallia.
A little bit about me
● In 2010 I joined Medallia.
● Super excited about building UI automation from scratch.
A little bit about me
● In 2014 moved to RelateIQ (Now SalesforceIQ)
A little bit about me
● In 2014 moved to RelateIQ (Now SalesforceIQ)
● Again a Start Up, being part of a small team that wanted to have a big
impact in the company.
A little bit about me
● Finally a couple of months ago I joined Split.IO.
A little bit about me
● Finally a couple of months ago I joined Split.IO
● Being one of the first Software Engineers, again with the role of shipping
code as fast as we can with the best Customer Experience as we can.
Episode I
WebDriver tests are inherently slow. If you want throughput, you need to
focus on parallelism, leading us to the first lesson in this saga.
Episode I: Data Independent Tests
If each test creates its own data that is not shared with anyone else, then all of
your tests can run in parallel.
To the code!
@Path(“/test”)
public class TestResource {
@Post
@Path(“create”)
public Response create(String uniqueUser) {
If (isProd()) { throw new NotAllowedException(“NOT ALLOWED”); }
//… create unique user, organization, etc...
//...
}
@Post
@Path(“clean”)
public Response clean(String uniqueUser) {
If (isProd()) { throw new NotAllowedException(“NOT ALLOWED”);}
//…clean unique user, organization, etc...
//...
}
}
To the code!
public class DataCreatorRule implements TestRule {
public Statement apply(Statement statement, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
String uniqueUser = "uniqueuser";
client
.test()
.create(uniqueUser);
statement.evaluate();
client
.test()
.clean(uniqueUser);
}
}
}
}
To the code!
public abstract class BaseTestCase {
@Rule
public DataCreatorRule dataCreatorRule =new DataCreatorRule();
}
Alternatives
● @BeforeMethod and @AfterMethod in TestNG.
● @Before and @After in JUnit < 4.
● beforeEach() and afterEach() in Jasmine JS.
● setUp(self) and tearDown(self) in Python.
Episode I Code Example
Episode II
Throughput is achieved with Parallelism. With that in mind, you need to build
reliable tests in all possible Environments.
Local != Staging != SauceLabs.
This leads to the second lesson...
Episode II: Slow and Steady Wins the Race
Failures are caused by elements not showing up in time. In general, when the
element has an unexpected transient state when the action is being
performed.
To the code!
private final Webdriver driver;
public void ohWhy(By identifier) {
Thread.sleep(3000);
WebElement element = driver.findElement(identifier);
element.click();
}
To the code!
private final Webdriver driver;
public void better(By identifier) {
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(identifier);
element.click();
}
To the code!
private final AugmentedWebDriver driver;
public void augmentedWay(By identifier) {
driver
.augmented()
.findElementClickable(identifier)
.click();
}
More...
driver.augmented().findElementVisible(id);
driver.augmented().findElementsVisible(id).get(0)
.augmented().findElementClickable(id2).click();
driver().augmented().clickAndSendKeys(id,“text”);
driver().augmented().swipeDown(id);
Episode II Code Example
Episode III.
● Your tests can run in parallel...
● You can wait until elements are on a desired state...
Time to encapsulate you tests in business logic to maximize reusability and
maintainability.
This leads to the third lesson...
Episode III: Follow the Page Object Model
Need to encapsulate the logic of the UI areas that your tests performs actions,
for maintainability and for many other reasons.
To the code!
public class MainPage extends WebPageObject {
@Override
public Optional<By> visibleBy() {
return Optional.of(Bys.INPUT);
}
public static class Bys {
public static class By INPUT = By.id("searchInput");
}
}
To the Code!
public class BaseCase extends AugmentedWebTestCase {
public MainPage mainPage() {
driver().get(“https://www.wikipedia.org”);
Return get(MainPage.class);
}
}
Episode III Code Example
Episode IV
● Your tests can run in parallel...
● You can wait until elements are on a desired state...
● You have your framework encapsulated on business logic…
The next level is to wait and expect certain business logic to take place when
actions are performed.
That leads to…
Episode IV: Wait and Expect for business logic
This is an extension of the Episode 2 but at a much higher level that each app
defines.
Episode IV: Wait and Expect for business logic
Since now we have Page Objects that encapsulate business logic, we can
perform “waiters” that will wait until certain condition is fulfilled.
To the Code!
public class MainPage extends WebPageObject {
public int numberOfSuggestions() {
return driver()
.augmented()
.findElementSSSSVisible(Bys.SUGGESTION)
.size();
}
public static class Bys {
public static final By SUGGESTION = By.className("suggestion-link");
}
}
To the Code!
@Test
public void test() {
mainPage
.search("WebDriver");
waiter().waitUntil(mainPage, page -> page.numberOfSuggestions() > 3);
}
Episode IV Code Example
Episode V
● Your tests can run in parallel...
● You can wait until elements are on a desired state...
● Your business logic is encapsulated...
● You can wait for business logic to be fulfilled…
Now each test has maintainability and reliability in mind. It’s time to
consolidate each individual piece into something that the rest of the team can
easily digest it.
Episode V: Reporting Reporting Reporting
This has one basic lesson learned:
Episode V
DON’T
Episode V Code Example
Episode VI
● Your tests can run in parallel...
● You can wait until elements are on a desired state...
● Your business logic is encapsulated...
● You can wait for business logic to be fulfilled…
● You have a way to have visibility and transparency
Finally the last step is to provide easy configuration and integrations so it can
be plugged into CI systems
Episode VI: Integrations and Easy Configuration
It should be easy and straightforward to integrate into different tools.
Episode VI Code Example
Thanks!
Augmented Driver: https://github.com/relateiq/AugmentedDriver
Split.IO: http://www.split.io/
Special offer by Applitools:
50-page guidebook to visual testing (including tips, tricks and code examples),
written by Selenium expert Dave Haeffner.
Claim your free copy by sending an email to webinars@applitools.com

Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando Martin)

  • 1.
    UI Automation atScale Augmented Driver [email protected]
  • 2.
    A little bitabout me ● Started working @Google in late 2006.
  • 3.
    A little bitabout me ● Started working @Google in late 2006. ● Selenium/Webdriver started becoming a “thing” sometime in 2007.
  • 4.
    A little bitabout me ● In 2010 I joined Medallia.
  • 5.
    A little bitabout me ● In 2010 I joined Medallia. ● Super excited about building UI automation from scratch.
  • 6.
    A little bitabout me ● In 2014 moved to RelateIQ (Now SalesforceIQ)
  • 7.
    A little bitabout me ● In 2014 moved to RelateIQ (Now SalesforceIQ) ● Again a Start Up, being part of a small team that wanted to have a big impact in the company.
  • 8.
    A little bitabout me ● Finally a couple of months ago I joined Split.IO.
  • 9.
    A little bitabout me ● Finally a couple of months ago I joined Split.IO ● Being one of the first Software Engineers, again with the role of shipping code as fast as we can with the best Customer Experience as we can.
  • 10.
    Episode I WebDriver testsare inherently slow. If you want throughput, you need to focus on parallelism, leading us to the first lesson in this saga.
  • 11.
    Episode I: DataIndependent Tests If each test creates its own data that is not shared with anyone else, then all of your tests can run in parallel.
  • 12.
    To the code! @Path(“/test”) publicclass TestResource { @Post @Path(“create”) public Response create(String uniqueUser) { If (isProd()) { throw new NotAllowedException(“NOT ALLOWED”); } //… create unique user, organization, etc... //... } @Post @Path(“clean”) public Response clean(String uniqueUser) { If (isProd()) { throw new NotAllowedException(“NOT ALLOWED”);} //…clean unique user, organization, etc... //... } }
  • 13.
    To the code! publicclass DataCreatorRule implements TestRule { public Statement apply(Statement statement, Description description) { return new Statement() { @Override public void evaluate() throws Throwable { String uniqueUser = "uniqueuser"; client .test() .create(uniqueUser); statement.evaluate(); client .test() .clean(uniqueUser); } } } }
  • 14.
    To the code! publicabstract class BaseTestCase { @Rule public DataCreatorRule dataCreatorRule =new DataCreatorRule(); }
  • 15.
    Alternatives ● @BeforeMethod and@AfterMethod in TestNG. ● @Before and @After in JUnit < 4. ● beforeEach() and afterEach() in Jasmine JS. ● setUp(self) and tearDown(self) in Python.
  • 16.
  • 17.
    Episode II Throughput isachieved with Parallelism. With that in mind, you need to build reliable tests in all possible Environments. Local != Staging != SauceLabs. This leads to the second lesson...
  • 18.
    Episode II: Slowand Steady Wins the Race Failures are caused by elements not showing up in time. In general, when the element has an unexpected transient state when the action is being performed.
  • 19.
    To the code! privatefinal Webdriver driver; public void ohWhy(By identifier) { Thread.sleep(3000); WebElement element = driver.findElement(identifier); element.click(); }
  • 20.
    To the code! privatefinal Webdriver driver; public void better(By identifier) { WebDriverWait wait = new WebDriverWait(driver, 10); WebElement element = wait.until(ExpectedConditions.elementToBeClickable(identifier); element.click(); }
  • 21.
    To the code! privatefinal AugmentedWebDriver driver; public void augmentedWay(By identifier) { driver .augmented() .findElementClickable(identifier) .click(); }
  • 22.
  • 23.
  • 24.
    Episode III. ● Yourtests can run in parallel... ● You can wait until elements are on a desired state... Time to encapsulate you tests in business logic to maximize reusability and maintainability. This leads to the third lesson...
  • 25.
    Episode III: Followthe Page Object Model Need to encapsulate the logic of the UI areas that your tests performs actions, for maintainability and for many other reasons.
  • 26.
    To the code! publicclass MainPage extends WebPageObject { @Override public Optional<By> visibleBy() { return Optional.of(Bys.INPUT); } public static class Bys { public static class By INPUT = By.id("searchInput"); } }
  • 27.
    To the Code! publicclass BaseCase extends AugmentedWebTestCase { public MainPage mainPage() { driver().get(“https://www.wikipedia.org”); Return get(MainPage.class); } }
  • 28.
  • 29.
    Episode IV ● Yourtests can run in parallel... ● You can wait until elements are on a desired state... ● You have your framework encapsulated on business logic… The next level is to wait and expect certain business logic to take place when actions are performed. That leads to…
  • 30.
    Episode IV: Waitand Expect for business logic This is an extension of the Episode 2 but at a much higher level that each app defines.
  • 31.
    Episode IV: Waitand Expect for business logic Since now we have Page Objects that encapsulate business logic, we can perform “waiters” that will wait until certain condition is fulfilled.
  • 32.
    To the Code! publicclass MainPage extends WebPageObject { public int numberOfSuggestions() { return driver() .augmented() .findElementSSSSVisible(Bys.SUGGESTION) .size(); } public static class Bys { public static final By SUGGESTION = By.className("suggestion-link"); } }
  • 33.
    To the Code! @Test publicvoid test() { mainPage .search("WebDriver"); waiter().waitUntil(mainPage, page -> page.numberOfSuggestions() > 3); }
  • 34.
  • 35.
    Episode V ● Yourtests can run in parallel... ● You can wait until elements are on a desired state... ● Your business logic is encapsulated... ● You can wait for business logic to be fulfilled… Now each test has maintainability and reliability in mind. It’s time to consolidate each individual piece into something that the rest of the team can easily digest it.
  • 36.
    Episode V: ReportingReporting Reporting This has one basic lesson learned:
  • 37.
  • 38.
  • 39.
    Episode VI ● Yourtests can run in parallel... ● You can wait until elements are on a desired state... ● Your business logic is encapsulated... ● You can wait for business logic to be fulfilled… ● You have a way to have visibility and transparency Finally the last step is to provide easy configuration and integrations so it can be plugged into CI systems
  • 40.
    Episode VI: Integrationsand Easy Configuration It should be easy and straightforward to integrate into different tools.
  • 41.
  • 42.
    Thanks! Augmented Driver: https://github.com/relateiq/AugmentedDriver Split.IO:http://www.split.io/ Special offer by Applitools: 50-page guidebook to visual testing (including tips, tricks and code examples), written by Selenium expert Dave Haeffner. Claim your free copy by sending an email to [email protected]