1
Wix Automation
Core
Roi Ashkenazi
Oded Gefen
2
Introduction
3
Introduction
Wix Editor
4
Modeling DOM Elements
5
Modeling DOM Elements
Concept
• Each editor component will have its own class (driver)
• Driver represents a DOM node and its sub DOM nodes
• ClassAPI will consist of methods returning sub drivers of the
component (building blocks)
• Methods can return other complex drivers or simple web
elements
6
Finding Elements
7
Finding Elements
Wix Editor
8
Finding Elements - Selenium
Wix Editor – Top Bar
public TopBar topBar() {
return getElement().byClass("top-bar-editor", TopBar.class);
}
9
Finding Elements - Selenium
TopBar.java - Driver
public Button preview() {
return getElement().byId("top-bar-preview", Button.class);
}
public Button undo() {
return getElement().byAttribute("automationId", "top-bar-undo",Button.class);
}
10
Finding Elements - JavaScript
• Re-written completely using React.js
• DOM nodes are less “rich” with information
• Need stable selectors to find elements
Wix Editor – Revisited
11
Finding Elements - JavaScript
Top Bar – React DOM
12
Finding Elements - JavaScript
TopBar.java - Driver
public PageNavButton pageNavigation() {
return getElement().byDisplayName("topBarPageNavButton", PageNavButton.class);
}
13
Finding Elements - Core
14
By - CSS
Concept
• Predefined methods for getting elements with different CSS
selectors
• Building the CSS selectors behind the scenes (transparent for
test code)
15
By - CSS
Standard examples
• byId (#)
• byClass (.)
• byAttribute ([attribute=‘value’])
• byCss(…)
Actual implementation
webDriver.findElement(By.cssSelector(selector));
16
By - DisplayName
Concept
• Find elements using “decorations” visible only in React DOM
• Use ReactTest Utilities (JavaScript)
public TopBar topBar() {
return getElement().byDisplayName("topBar", TopBar.class);
}
17
By - DisplayName
Actual implementation
Executing script located in client project:
- Pass display name string as script argument
- Script returns a corresponding list of seleniumWebElements
- Usage of findAllInRenderedTree method from ReactTest Utilities inside script
implementation
domSelectors.getElementsByDisplayName(arguments[0]);
18
By - DisplayName
Actual implementation
Stream<WebElementProxy> searchElements(WebElementProxy root) {
List elements = (List) executeScript(...);
return Stream.of(elements.toArray())
.filter(Objects::nonNull)
.map(WebElement.class::cast)
.map(WebElementProxy::new);
}
WebElementProxy searchElement(WebElementProxy root) {
return searchElements(root)
.findFirst()
.orElseThrow(() ->
new RuntimeException("Failed to get element " + this));
}
19
Wrapping Native Selenium
20
Wrapping Native Selenium
Concept
Wrapping useful selenium commands in our infrastructure
• Allows to change behavior of basic commands (e.g. wait after
click)
• Combine several actions together and create new actions (drag
and drop)
• Add smart waits instead of sleep
21
Wrapping WebDriver
API
• Navigation
 Open URL in new window
 Close extra tabs
 Switch focus to last window
 Wait for number of windows to be (etc..)
• Logs
 Network
 Console errors
• Cookies
 Add
 Find
 Remove
22
Wrapping WebDriver
API
• Navigation
 Open URL in new window
 Close extra tabs
 Switch focus to last window
 Wait for number of windows to be (etc..)
• Logs
 Network
 Console errors
• Cookies
 Add
 Find
 Remove
23
Wrapping WebDriver
API – Navigation – Open URL in new window
public void openUrlInNewWindow(String url) {
webDriver.executeScript("window.open()");
Object[] windowHandles = webDriver.getWindowHandles().toArray();
int numberOfWindows = windowHandles.size();
String targetWindowHandle = (String) windowHandles[numberOfWindows - 1];
webDriver.switchTo().window(targetWindowHandle);
webDriver.manage().window().maximize();
webDriver.get(url);
}
24
Wrapping WebElement
API
• Actions
• Attributes
• ElementWaitFor
25
Wrapping WebElement
API
• Actions
• Attributes
• ElementWaitFor
26
Wrapping WebElement
API – Actions
• dragAndDrop
• clickAtOffset
• doubleClick
• mouseMoveToElement
• setText
• rightClick
27
Wrapping WebElement
API – Actions
• dragAndDrop
• clickAtOffset
• doubleClick
• mouseMoveToElement
• setText
• rightClick
28
Wrapping WebElement
API – Actions – Drag and drop
public void dragAndDrop(int xOffset, int yOffset) {
Actions actions = new Actions(webDriver);
actions.clickAndHold(webElement)
.moveByOffset(xOffset, yOffset)
.release()
.perform();
}
29
Wrapping WebElement
API
• Actions
• Attributes
• ElementWaitFor
30
Wrapping WebElement
API – Attributes
• getInnerHTML
• getId
• getCssClasses
• getSize
• getText
• getPosition
• isVisible
• isEnabled
31
Wrapping WebElement
API – Attributes
• getInnerHTML
• getId
• getCssClasses
• getSize
• getText
• getPosition
• isVisible
• isEnabled
32
Wrapping WebElement
API – Attributes – Get inner HTML
public String getInnerHTML() {
String script = "return arguments[0].innerHTML;";
return (String) webDriver.executeScript(script, webElement);
}
33
Wrapping WebElement
API
• Actions
• Attributes
• ElementWaitFor
34
Wrapping WebElement
API – ElementWaitFor
• attributeToBe
• toExist
• toBeDisplayed
• textToBe
• toContainsCssClass
35
Wrapping WebElement
API – ElementWaitFor
• attributeToBe
• toExist
• toBeDisplayed
• textToBe
• toContainsCssClass
36
Wrapping WebElement
API – ElementWaitFor – Wait for attribute to be
public void attributeToBe(String attribute, String value) {
BusyWait.create(TIMEOUT,
POLLING_INTERVAL,
__ -> webElement.getAttribute(attribute).equals(value))
.execute();
}
37
Wrapping WebElement
API – ElementWaitFor – Wait for attribute to be
public void attributeToBe(String attribute, String value) {
BusyWait.create(TIMEOUT,
POLLING_INTERVAL,
__ -> webElement.getAttribute(attribute).equals(value))
.execute();
}
topBar.waitFor().attributeToBe(”state”, ”noErrors”);
38
39
Iframes
Concept
• Each element “knows” if it’s inside an iframe
• Each driver “knows” if it contains an iframe
• Getting an element inside the iframe is done differently
40
Iframes
@Iframe
class CKEditor extends Input {
public TextContainer textContainer() {
return getIframeElement().byCss("h1", TextContainer.class);
}
public Button bold() {
return getElement().byId(”boldBtn", Button.class);
}
}
41

Wix Automation - Core

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
    5 Modeling DOM Elements Concept •Each editor component will have its own class (driver) • Driver represents a DOM node and its sub DOM nodes • ClassAPI will consist of methods returning sub drivers of the component (building blocks) • Methods can return other complex drivers or simple web elements
  • 6.
  • 7.
  • 8.
    8 Finding Elements -Selenium Wix Editor – Top Bar public TopBar topBar() { return getElement().byClass("top-bar-editor", TopBar.class); }
  • 9.
    9 Finding Elements -Selenium TopBar.java - Driver public Button preview() { return getElement().byId("top-bar-preview", Button.class); } public Button undo() { return getElement().byAttribute("automationId", "top-bar-undo",Button.class); }
  • 10.
    10 Finding Elements -JavaScript • Re-written completely using React.js • DOM nodes are less “rich” with information • Need stable selectors to find elements Wix Editor – Revisited
  • 11.
    11 Finding Elements -JavaScript Top Bar – React DOM
  • 12.
    12 Finding Elements -JavaScript TopBar.java - Driver public PageNavButton pageNavigation() { return getElement().byDisplayName("topBarPageNavButton", PageNavButton.class); }
  • 13.
  • 14.
    14 By - CSS Concept •Predefined methods for getting elements with different CSS selectors • Building the CSS selectors behind the scenes (transparent for test code)
  • 15.
    15 By - CSS Standardexamples • byId (#) • byClass (.) • byAttribute ([attribute=‘value’]) • byCss(…) Actual implementation webDriver.findElement(By.cssSelector(selector));
  • 16.
    16 By - DisplayName Concept •Find elements using “decorations” visible only in React DOM • Use ReactTest Utilities (JavaScript) public TopBar topBar() { return getElement().byDisplayName("topBar", TopBar.class); }
  • 17.
    17 By - DisplayName Actualimplementation Executing script located in client project: - Pass display name string as script argument - Script returns a corresponding list of seleniumWebElements - Usage of findAllInRenderedTree method from ReactTest Utilities inside script implementation domSelectors.getElementsByDisplayName(arguments[0]);
  • 18.
    18 By - DisplayName Actualimplementation Stream<WebElementProxy> searchElements(WebElementProxy root) { List elements = (List) executeScript(...); return Stream.of(elements.toArray()) .filter(Objects::nonNull) .map(WebElement.class::cast) .map(WebElementProxy::new); } WebElementProxy searchElement(WebElementProxy root) { return searchElements(root) .findFirst() .orElseThrow(() -> new RuntimeException("Failed to get element " + this)); }
  • 19.
  • 20.
    20 Wrapping Native Selenium Concept Wrappinguseful selenium commands in our infrastructure • Allows to change behavior of basic commands (e.g. wait after click) • Combine several actions together and create new actions (drag and drop) • Add smart waits instead of sleep
  • 21.
    21 Wrapping WebDriver API • Navigation Open URL in new window  Close extra tabs  Switch focus to last window  Wait for number of windows to be (etc..) • Logs  Network  Console errors • Cookies  Add  Find  Remove
  • 22.
    22 Wrapping WebDriver API • Navigation Open URL in new window  Close extra tabs  Switch focus to last window  Wait for number of windows to be (etc..) • Logs  Network  Console errors • Cookies  Add  Find  Remove
  • 23.
    23 Wrapping WebDriver API –Navigation – Open URL in new window public void openUrlInNewWindow(String url) { webDriver.executeScript("window.open()"); Object[] windowHandles = webDriver.getWindowHandles().toArray(); int numberOfWindows = windowHandles.size(); String targetWindowHandle = (String) windowHandles[numberOfWindows - 1]; webDriver.switchTo().window(targetWindowHandle); webDriver.manage().window().maximize(); webDriver.get(url); }
  • 24.
    24 Wrapping WebElement API • Actions •Attributes • ElementWaitFor
  • 25.
    25 Wrapping WebElement API • Actions •Attributes • ElementWaitFor
  • 26.
    26 Wrapping WebElement API –Actions • dragAndDrop • clickAtOffset • doubleClick • mouseMoveToElement • setText • rightClick
  • 27.
    27 Wrapping WebElement API –Actions • dragAndDrop • clickAtOffset • doubleClick • mouseMoveToElement • setText • rightClick
  • 28.
    28 Wrapping WebElement API –Actions – Drag and drop public void dragAndDrop(int xOffset, int yOffset) { Actions actions = new Actions(webDriver); actions.clickAndHold(webElement) .moveByOffset(xOffset, yOffset) .release() .perform(); }
  • 29.
    29 Wrapping WebElement API • Actions •Attributes • ElementWaitFor
  • 30.
    30 Wrapping WebElement API –Attributes • getInnerHTML • getId • getCssClasses • getSize • getText • getPosition • isVisible • isEnabled
  • 31.
    31 Wrapping WebElement API –Attributes • getInnerHTML • getId • getCssClasses • getSize • getText • getPosition • isVisible • isEnabled
  • 32.
    32 Wrapping WebElement API –Attributes – Get inner HTML public String getInnerHTML() { String script = "return arguments[0].innerHTML;"; return (String) webDriver.executeScript(script, webElement); }
  • 33.
    33 Wrapping WebElement API • Actions •Attributes • ElementWaitFor
  • 34.
    34 Wrapping WebElement API –ElementWaitFor • attributeToBe • toExist • toBeDisplayed • textToBe • toContainsCssClass
  • 35.
    35 Wrapping WebElement API –ElementWaitFor • attributeToBe • toExist • toBeDisplayed • textToBe • toContainsCssClass
  • 36.
    36 Wrapping WebElement API –ElementWaitFor – Wait for attribute to be public void attributeToBe(String attribute, String value) { BusyWait.create(TIMEOUT, POLLING_INTERVAL, __ -> webElement.getAttribute(attribute).equals(value)) .execute(); }
  • 37.
    37 Wrapping WebElement API –ElementWaitFor – Wait for attribute to be public void attributeToBe(String attribute, String value) { BusyWait.create(TIMEOUT, POLLING_INTERVAL, __ -> webElement.getAttribute(attribute).equals(value)) .execute(); } topBar.waitFor().attributeToBe(”state”, ”noErrors”);
  • 38.
  • 39.
    39 Iframes Concept • Each element“knows” if it’s inside an iframe • Each driver “knows” if it contains an iframe • Getting an element inside the iframe is done differently
  • 40.
    40 Iframes @Iframe class CKEditor extendsInput { public TextContainer textContainer() { return getIframeElement().byCss("h1", TextContainer.class); } public Button bold() { return getElement().byId(”boldBtn", Button.class); } }
  • 41.