Download - Wix Automation - Core
1
Wix AutomationCore
Roi AshkenaziOded Gefen
2
Introduction
3
IntroductionWix Editor
4
Modeling DOM Elements
5
Modeling DOM ElementsConcept• Each editor component will have its own class
(driver)• Driver represents a DOM node and its sub DOM
nodes• Class API 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 ElementsWix Editor
8
Finding Elements - SeleniumWix Editor – Top Bar
public TopBar topBar() { return getElement().byClass("top-bar-editor", TopBar.class);}
9
Finding Elements - SeleniumTopBar.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 - JavaScriptTop Bar – React DOM
12
Finding Elements - JavaScriptTopBar.java - Driver
public PageNavButton pageNavigation() { return getElement().byDisplayName("topBarPageNavButton", PageNavButton.class);}
13
Finding Elements - Core
14
By - CSSConcept• Predefined methods for getting elements with
different CSS selectors• Building the CSS selectors behind the scenes
(transparent for test code)
15
By - CSSStandard examples• byId (#)• byClass (.)• byAttribute ([attribute=‘value’])• byCss(…)
Actual implementationwebDriver.findElement(By.cssSelector(selector));
16
By - DisplayName Concept• Find elements using “decorations” visible only in React DOM• Use React Test Utilities (JavaScript)
public TopBar topBar() { return getElement().byDisplayName("topBar", TopBar.class);}
17
By - DisplayNameActual implementation
Executing script located in client project:
- Pass display name string as script argument- Script returns a corresponding list of selenium WebElements - Usage of findAllInRenderedTree method from React Test
Utilities inside script implementation
domSelectors.getElementsByDisplayName(arguments[0]);
18
By - DisplayNameActual implementationStream<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 SeleniumConceptWrapping 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 WebDriverAPI• 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 WebDriverAPI• 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 WebDriverAPI – 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 WebElementAPI
• Actions• Attributes• ElementWaitFor
25
Wrapping WebElementAPI
• Actions• Attributes• ElementWaitFor
26
Wrapping WebElementAPI – Actions
• dragAndDrop• clickAtOffset• doubleClick• mouseMoveToElement• setText• rightClick
27
Wrapping WebElementAPI – Actions
• dragAndDrop• clickAtOffset• doubleClick• mouseMoveToElement• setText• rightClick
28
Wrapping WebElementAPI – 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 WebElementAPI
• Actions• Attributes• ElementWaitFor
30
Wrapping WebElementAPI – Attributes
• getInnerHTML• getId• getCssClasses• getSize• getText• getPosition• isVisible• isEnabled
31
Wrapping WebElementAPI – Attributes
• getInnerHTML• getId• getCssClasses• getSize• getText• getPosition• isVisible• isEnabled
32
Wrapping WebElementAPI – Attributes – Get inner HTML
public String getInnerHTML() { String script = "return arguments[0].innerHTML;"; return (String) webDriver.executeScript(script, webElement);}
33
Wrapping WebElementAPI
• Actions• Attributes• ElementWaitFor
34
Wrapping WebElementAPI – ElementWaitFor
• attributeToBe• toExist• toBeDisplayed• textToBe• toContainsCssClass
35
Wrapping WebElementAPI – ElementWaitFor
• attributeToBe• toExist• toBeDisplayed• textToBe• toContainsCssClass
36
Wrapping WebElementAPI – 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 WebElementAPI – 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
IframesConcept
• 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