PageRenderTime 26ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/atlassian-webdriver/atlassian-webdriver-core/src/main/java/com/atlassian/webdriver/visualcomparison/WebDriverBrowserEngine.java

https://bitbucket.org/atlassian/atlassian-selenium
Java | 188 lines | 156 code | 27 blank | 5 comment | 1 complexity | f56d8798abdede8604a9eee65e186dad MD5 | raw file
  1. package com.atlassian.webdriver.visualcomparison;
  2. import com.atlassian.selenium.visualcomparison.ScreenElement;
  3. import com.atlassian.selenium.visualcomparison.v2.BrowserEngine;
  4. import com.atlassian.selenium.visualcomparison.v2.settings.Resolution;
  5. import com.atlassian.webdriver.debug.WebDriverDebug;
  6. import org.openqa.selenium.*;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9. import javax.annotation.Nonnull;
  10. import javax.annotation.Nullable;
  11. import javax.inject.Inject;
  12. import java.io.File;
  13. import java.util.Collections;
  14. import java.util.List;
  15. import static com.atlassian.webdriver.utils.JavaScriptUtils.execute;
  16. import static java.lang.String.format;
  17. import static java.util.Objects.requireNonNull;
  18. /**
  19. * @since 2.3
  20. */
  21. public final class WebDriverBrowserEngine implements BrowserEngine
  22. {
  23. private static final Logger log = LoggerFactory.getLogger(WebDriverBrowserEngine.class);
  24. private final WebDriver webDriver;
  25. @Inject
  26. public WebDriverBrowserEngine(@Nonnull WebDriver webDriver)
  27. {
  28. this.webDriver = requireNonNull(webDriver, "webDriver");
  29. }
  30. @SuppressWarnings("ConstantConditions")
  31. @Nonnull
  32. @Override
  33. public ScreenElement getElementAt(int x, int y)
  34. {
  35. try
  36. {
  37. ElementByPoint elementByPoint = new ElementByPoint(x, y).calculate();
  38. // scroll to put the element in viewport
  39. executeScript(Object.class, format("window.scrollTo(%d,%d)",
  40. elementByPoint.scrollTo.getX(), elementByPoint.scrollTo.getY()));
  41. final WebElement element = webDriver.findElement(byPoint(elementByPoint.elementCoordinates));
  42. return new SimpleScreenElement(executeScript(String.class,
  43. "var d = document.createElement('div'); d.appendChild(arguments[0].cloneNode(true)); return d.innerHTML;",
  44. element));
  45. }
  46. catch (Exception e)
  47. {
  48. log.error(format("Error while getting screen element at %d,%d", x, y), e);
  49. return new SimpleScreenElement("");
  50. }
  51. }
  52. @Nonnull
  53. @Override
  54. public BrowserEngine resizeTo(@Nonnull Resolution resolution)
  55. {
  56. setSize(resolution);
  57. // NOT a mistake... WebDriver sometimes needs an extra kick in butt
  58. setSize(resolution);
  59. return this;
  60. }
  61. @Nonnull
  62. @Override
  63. public BrowserEngine captureScreenshotTo(@Nonnull File file)
  64. {
  65. new WebDriverDebug(webDriver).takeScreenshotTo(file);
  66. return this;
  67. }
  68. @Nonnull
  69. @Override
  70. public BrowserEngine reloadPage()
  71. {
  72. webDriver.navigate().refresh();
  73. return this;
  74. }
  75. @Nullable
  76. @Override
  77. public <T> T executeScript(@Nonnull Class<T> returnType, @Nonnull String script, @Nonnull Object... args)
  78. {
  79. return execute(returnType, script, webDriver, args);
  80. }
  81. private By byPoint(final Point coordinates)
  82. {
  83. return new By()
  84. {
  85. @Override
  86. public List<WebElement> findElements(SearchContext context)
  87. {
  88. final String findByPoint = format("return document.elementFromPoint(%d,%d);", coordinates.getX(),
  89. coordinates.getY());
  90. final WebElement element = execute(WebElement.class, findByPoint, webDriver);
  91. return element != null ? Collections.singletonList(element) : Collections.<WebElement>emptyList();
  92. }
  93. @Override
  94. public String toString()
  95. {
  96. return format("By point in viewport %d,%d", coordinates.getX(), coordinates.getY());
  97. }
  98. };
  99. }
  100. @SuppressWarnings("ConstantConditions")
  101. private Dimension getDimensionFor(String selector)
  102. {
  103. long x = executeScript(Long.class, "return jQuery(" + selector + ").width();");
  104. long y = executeScript(Long.class, "return jQuery(" + selector + ").height();");
  105. return new Dimension((int) x, (int) y);
  106. }
  107. private void setSize(Resolution resolution)
  108. {
  109. webDriver.manage().window().setSize(new Dimension(resolution.getWidth(), resolution.getHeight()));
  110. }
  111. private final class ElementByPoint
  112. {
  113. private final int x;
  114. private final int y;
  115. private Dimension viewport;
  116. private Dimension document;
  117. Point scrollTo;
  118. Point elementCoordinates;
  119. private ElementByPoint(int x, int y)
  120. {
  121. this.x = x;
  122. this.y = y;
  123. }
  124. ElementByPoint calculate()
  125. {
  126. this.document = getDimensionFor("document");
  127. this.viewport = getDimensionFor("window");
  128. calculateScroll();
  129. calculateCoordinates();
  130. return this;
  131. }
  132. private void calculateScroll()
  133. {
  134. int deltaX = Math.max(0, document.getWidth() - viewport.getWidth());
  135. int scrollX = Math.min(x, deltaX);
  136. int deltaY = Math.max(0, document.getHeight() - viewport.getHeight());
  137. int scrollY = Math.min(y, deltaY);
  138. scrollTo = new Point(scrollX, scrollY);
  139. }
  140. private void calculateCoordinates()
  141. {
  142. int relativeX = x - scrollTo.getX();
  143. int relativeY = y - scrollTo.getY();
  144. elementCoordinates = new Point(relativeX, relativeY);
  145. }
  146. }
  147. private static final class SimpleScreenElement implements ScreenElement
  148. {
  149. private final String html;
  150. private SimpleScreenElement(@Nonnull String html)
  151. {
  152. this.html = html;
  153. }
  154. @Override
  155. @Nonnull
  156. public String getHtml()
  157. {
  158. return html;
  159. }
  160. }
  161. }