Java tutorial
/* * Copyright (c) 2018, salesforce.com, inc. * All rights reserved. * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ package com.salesforce.selenium.support.event; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import com.fasterxml.jackson.annotation.JsonIgnore; /** * Records information on a given WebDriver command such as click() or getText(). * * The {@link EventFiringWebDriver} creates such a record before and after each command. The Step object * is then passed on to any listeners implementing the {@link WebDriverEventListener} interface. * * A special listener is {@link FullJSONLogger} which collects all Step objects and saves the collection * to a JSON file. * * @author gneumann * @since 2.0.0 */ public class Step { public enum Type { BeforeAction, AfterAction, BeforeGather, AfterGather, Exception } // TODO add Alert public enum WebDriverInterface { WebDriver, JavascriptExecutor, Navigation, TargetLocator, Timeouts, Window, WebElement } public enum Cmd { // commands called directly from WebDriver object close(WebDriverInterface.WebDriver, "close"), findElementByWebDriver(WebDriverInterface.WebDriver, "findElement"), findElementsByWebDriver(WebDriverInterface.WebDriver, "findElements"), get( WebDriverInterface.WebDriver, "get"), getCurrentUrl(WebDriverInterface.WebDriver, "getCurrentUrl"), getPageSource( WebDriverInterface.WebDriver, "getPageSource"), getTitle( WebDriverInterface.WebDriver, "getTitle"), getWindowHandle( WebDriverInterface.WebDriver, "getWindowHandle"), getWindowHandles( WebDriverInterface.WebDriver, "getWindowHandles"), quit( WebDriverInterface.WebDriver, "quit"), // commands called directly from WebDriver object after casting to JavascriptExecutor executeAsyncScript(WebDriverInterface.JavascriptExecutor, "executeAsyncScript"), executeScript(WebDriverInterface.JavascriptExecutor, "executeScript"), // commands called directly from WebDriver.Navigation object back(WebDriverInterface.Navigation, "back"), forward(WebDriverInterface.Navigation, "forward"), refresh( WebDriverInterface.Navigation, "refresh"), to(WebDriverInterface.Navigation, "to"), // commands called directly from WebDriver.TargetLocator object activeElement(WebDriverInterface.TargetLocator, "activeElement"), alert(WebDriverInterface.TargetLocator, "alert"), defaultContent(WebDriverInterface.TargetLocator, "defaultContent"), frameByIndex( WebDriverInterface.TargetLocator, "frame"), frameByName(WebDriverInterface.TargetLocator, "frame"), frameByElement(WebDriverInterface.TargetLocator, "frame"), parentFrame( WebDriverInterface.TargetLocator, "parentFrame"), window(WebDriverInterface.TargetLocator, "window"), // commands called directly from WebDriver.Timeouts object implicitlyWait(WebDriverInterface.Timeouts, "implicitlyWait"), pageLoadTimeout(WebDriverInterface.Timeouts, "pageLoadTimeout"), setScriptTimeout(WebDriverInterface.Timeouts, "setScriptTimeout"), // commands called directly from WebDriver.Window object fullscreen(WebDriverInterface.Window, "fullscreen"), getPosition(WebDriverInterface.Window, "getPosition"), getSize(WebDriverInterface.Window, "getSize"), maximize(WebDriverInterface.Window, "maximize"), setPosition(WebDriverInterface.Window, "setPosition"), setSize(WebDriverInterface.Window, "setSize"), // commands called directly from WebElement object clickByElement(WebDriverInterface.WebElement, "click"), clear(WebDriverInterface.WebElement, "clear"), findElementByElement(WebDriverInterface.WebElement, "findElement"), findElementsByElement( WebDriverInterface.WebElement, "findElements"), getAttribute(WebDriverInterface.WebElement, "getAttribute"), getCssValue( WebDriverInterface.WebElement, "getCssValue"), getTagName(WebDriverInterface.WebElement, "getTagName"), getText( WebDriverInterface.WebElement, "getText"), isDisplayed(WebDriverInterface.WebElement, "isDisplayed"), isEnabled(WebDriverInterface.WebElement, "isEnabled"), isSelected(WebDriverInterface.WebElement, "isSelected"), sendKeysByElement( WebDriverInterface.WebElement, "sendKeys"), submit( WebDriverInterface.WebElement, "submit"); private Cmd(WebDriverInterface wdIf, String shortCmdString) { this.wdIf = wdIf; this.shortCmdString = shortCmdString; } private final WebDriverInterface wdIf; private final String shortCmdString; public String getShortCmdString() { return this.shortCmdString; } public WebDriverInterface getWebDriverInterface() { return this.wdIf; } public String getLongCmdString() { return (this.wdIf == WebDriverInterface.WebElement) ? getLongCmdString("webElement") : getLongCmdString("webDriver"); } public String getLongCmdString(String fieldName) { String value = null; String shortCmd = getShortCmdString(); switch (this.wdIf) { case WebDriver: value = fieldName + "." + shortCmd; break; case JavascriptExecutor: value = "(JavascriptExecutor) " + fieldName + "." + shortCmd; break; case Navigation: value = fieldName + ".navigate()." + shortCmd; break; case TargetLocator: value = fieldName + ".switchTo()." + shortCmd; break; case Timeouts: value = fieldName + ".timeouts()." + shortCmd; break; case Window: value = fieldName + ".manage().window()." + shortCmd; break; case WebElement: value = fieldName + "." + shortCmd; break; } return value; } } private static long timeMarkerElapsedStep; private static long timeMarkerSinceLastStep; private static int lastRecordNumber = 1; private int recordNumber = -1; private int stepNumber = -1; private long timeStamp = -1L; // System.currentTimeMillis() private long timeSinceLastAction = -1L; // measured from end of last action to begin of current action private long timeElapsedStep = -1L; // measured from begin of current command to end of current command private Type typeOfLog; private Cmd cmd; private String param1; private String param2; private String returnValue; @JsonIgnore private Object returnObject; private Throwable issue; private String elementLocator; /** * Empty Default constructor to be used by de-serialization. */ public Step() { // no-op } public Step(Type typeOfLog, int stepNumber, Cmd cmd) { this.recordNumber = Step.lastRecordNumber++; this.typeOfLog = typeOfLog; this.stepNumber = stepNumber; this.cmd = cmd; this.timeStamp = System.currentTimeMillis(); switch (typeOfLog) { case BeforeAction: timeStampsForBeginAction(); timeStampsForBeginStep(); break; case AfterAction: timeStampsForAfterAction(); timeStampsForAfterStep(); break; case BeforeGather: timeStampsForBeginStep(); break; case AfterGather: timeStampsForAfterStep(); break; default: } } public int getRecordNumber() { return recordNumber; } public void setRecordNumber(int recordNumber) { this.recordNumber = recordNumber; } public int getStepNumber() { return stepNumber; } public void setStepNumber(int stepNumber) { this.stepNumber = stepNumber; } public long getTimeStamp() { return timeStamp; } public void setTimeStamp(long timeStamp) { this.timeStamp = timeStamp; } public long getTimeSinceLastAction() { return timeSinceLastAction; } public void setTimeSinceLastAction(long timeSinceLastStep) { this.timeSinceLastAction = timeSinceLastStep; } public long getTimeElapsedStep() { return timeElapsedStep; } public void setTimeElapsedStep(long timeElapsedStep) { this.timeElapsedStep = timeElapsedStep; } public Type getTypeOfLog() { return typeOfLog; } public void setTypeOfLog(Type typeOfLog) { this.typeOfLog = typeOfLog; } public Cmd getCmd() { return cmd; } public void setCmd(Cmd cmd) { this.cmd = cmd; } public String getParam1() { return param1; } public void setParam1(String param1) { this.param1 = param1; } public String getParam2() { return param2; } public void setParam2(String param2) { this.param2 = param2; } public String getReturnValue() { return returnValue; } public void setReturnValue(String returnValue) { this.returnValue = returnValue; } public Object getReturnObject() { return returnObject; } public void setReturnObject(Object returnObject) { this.returnObject = returnObject; } public Throwable getIssue() { return issue; } public void setIssue(Throwable issue) { this.issue = issue; } public String getElementLocator() { return elementLocator; } public void setElementLocator(String elementLocator) { this.elementLocator = elementLocator; } @Override public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("stepno:").append(stepNumber).append(","); buffer.append("type:").append(typeOfLog).append(","); buffer.append("timestamp:").append(timeStamp).append(" ms,"); buffer.append("cmd:").append(cmd); if (param1 != null) { buffer.append(",").append("param1:").append(param1); } if (param2 != null) { buffer.append(",").append("param2:").append(param2); } if (returnValue != null) { buffer.append(",").append("returned:").append(returnValue).append(","); } if (returnObject != null) { buffer.append(",").append("returned:").append(returnObject.toString()).append(","); } if (timeSinceLastAction != -1L) { buffer.append(",").append("since last step:").append(formattedNanoTime(timeSinceLastAction)); } if (timeElapsedStep != -1L) { buffer.append(",").append("executed in:").append(formattedNanoTime(timeElapsedStep)); } if (issue != null) { buffer.append(",").append("issue:").append(issue.getMessage()); } return buffer.toString(); } public static String formattedNanoTime(long duration) { String timeString = String.format("%d sec %d ms", TimeUnit.NANOSECONDS.toSeconds(duration), TimeUnit.NANOSECONDS.toMillis(duration) - TimeUnit.SECONDS.toMillis(TimeUnit.NANOSECONDS.toSeconds(duration))); return timeString; } private void timeStampsForBeginAction() { if (stepNumber > 1) { timeSinceLastAction = System.nanoTime() - timeMarkerSinceLastStep; } } private void timeStampsForAfterAction() { timeMarkerSinceLastStep = System.nanoTime(); } private void timeStampsForBeginStep() { timeMarkerElapsedStep = System.nanoTime(); } private void timeStampsForAfterStep() { timeElapsedStep = System.nanoTime() - timeMarkerElapsedStep; } public static String getLocatorFromWebElement(WebElement elem) { return (elem != null) ? getLocatorFromWebElement(elem.toString()) : null; } public static String getLocatorFromWebElement(String locator) { if (locator == null) return null; // sample string: // "[[RemoteWebDriver: firefox on WINDOWS (a66f78e9668e4aa3b066239459f969fe)] -> xpath: .//*[@id='Country__c_body']/table/tbody/tr[2]/th/a]" Pattern outerPattern = Pattern.compile("(\\[\\[.+\\] -> )(.+)\\]"); Matcher outerMatcher = outerPattern.matcher(locator); if (!outerMatcher.matches()) { // return toString() as-is return locator; } // try to get the locator locator = locator.substring(outerMatcher.start(2), outerMatcher.end(2)); // sample string: // "xpath: .//*[@id='Country__c_body']/table/tbody/tr[2]/th/a]" Pattern innerPattern = Pattern.compile("(\\S+): (.+)"); Matcher innerMatcher = innerPattern.matcher(locator); boolean isLinkText = false; if (!innerMatcher.matches()) { innerPattern = Pattern.compile("(link text): (.+)"); innerMatcher = innerPattern.matcher(locator); if (innerMatcher.matches()) { isLinkText = true; } else { // return what we got with the outer matcher return locator; } } // build the @FindBy string StringBuilder sb = new StringBuilder(); sb.append("By."); // append locator type: "xpath" String locatorType = (isLinkText) ? "linkText" : locator.substring(innerMatcher.start(1), innerMatcher.end(1)); sb.append(locatorType).append("(\""); // append locator itself: ".//*[@id='Country__c_body']/table/tbody/tr[2]/th/a]" sb.append(locator.substring(innerMatcher.start(2), innerMatcher.end(2))).append("\")"); return sb.toString(); } public static String getLocatorFromBy(By by) { return (by != null) ? getLocatorFromBy(by.toString()) : null; } public static String getLocatorFromBy(String locator) { if (locator == null) return null; // sample string: // "By.xpath: .//*[@id='thePage:j_id39:searchblock:test:j_id45_lkwgt']/img" Pattern pattern = Pattern.compile("By.(\\S+): (.+)"); Matcher matcher = pattern.matcher(locator); if (!matcher.matches()) { // return what we got as-is return locator; } // build the @FindBy string StringBuilder sb = new StringBuilder(); sb.append("By."); // append locator type: "xpath" sb.append(locator.substring(matcher.start(1), matcher.end(1))).append("(\""); // append locator itself: // ".//*[@id='thePage:j_id39:searchblock:test:j_id45_lkwgt']/img" sb.append(locator.substring(matcher.start(2), matcher.end(2))).append("\")"); return sb.toString(); } }