aboutsummaryrefslogtreecommitdiffstats
path: root/tests/src/test/java/util/selenium/SeleneseRunner.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/test/java/util/selenium/SeleneseRunner.java')
-rw-r--r--tests/src/test/java/util/selenium/SeleneseRunner.java440
1 files changed, 440 insertions, 0 deletions
diff --git a/tests/src/test/java/util/selenium/SeleneseRunner.java b/tests/src/test/java/util/selenium/SeleneseRunner.java
new file mode 100644
index 00000000000..96cc4e609a2
--- /dev/null
+++ b/tests/src/test/java/util/selenium/SeleneseRunner.java
@@ -0,0 +1,440 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package util.selenium;
+
+import com.sonar.orchestrator.Orchestrator;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+import org.assertj.core.util.Strings;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.NotFoundException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.logging.LogEntries;
+import org.openqa.selenium.logging.LogEntry;
+import org.openqa.selenium.logging.LogType;
+import org.sonarqube.pageobjects.SelenideConfig;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Objects.requireNonNull;
+import static java.util.regex.Pattern.DOTALL;
+import static org.assertj.core.api.Assertions.assertThat;
+import static util.selenium.Retry._30_SECONDS;
+
+class SeleneseRunner {
+
+ private Map<String, String> variables;
+ private String baseUrl;
+ private WebDriver driver;
+
+ void runOn(Selenese selenese, Orchestrator orchestrator) {
+ this.variables = new HashMap<>();
+ this.baseUrl = orchestrator.getServer().getUrl();
+ this.driver = SelenideConfig.configure(orchestrator);
+
+ driver.manage().deleteAllCookies();
+
+ for (File file : selenese.getHtmlTests()) {
+ System.out.println();
+ System.out.println("============ " + file.getName() + " ============");
+ Document doc = parse(file);
+ for (Element table : doc.getElementsByTag("table")) {
+ for (Element tbody : table.getElementsByTag("tbody")) {
+ for (Element tr : tbody.getElementsByTag("tr")) {
+ String action = tr.child(0).text();
+ String param1 = tr.child(1).text();
+ String param2 = tr.child(2).text();
+
+ try {
+ action(action, param1, param2);
+ } catch (AssertionError e) {
+ analyzeLog(driver);
+ throw e;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static void analyzeLog(WebDriver driver) {
+ LogEntries logEntries = driver.manage().logs().get(LogType.BROWSER);
+ for (LogEntry entry : logEntries) {
+ System.out.println(new Date(entry.getTimestamp()) + " " + entry.getLevel() + " " + entry.getMessage());
+ }
+ }
+
+ private static Document parse(File file) {
+ try {
+ return Jsoup.parse(file, UTF_8.name());
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to parse file: " + file, e);
+ }
+ }
+
+ public SeleneseRunner action(String action, String param1, String param2) {
+ switch (action) {
+ case "open":
+ open(param1);
+ return this;
+ case "type":
+ type(param1, param2);
+ return this;
+ case "keyPressAndWait":
+ keyPressAndWait(param1, param2);
+ return this;
+ case "select":
+ select(param1, param2);
+ return this;
+ case "clickAndWait":
+ case "click":
+ click(param1);
+ return this;
+ case "check":
+ check(param1);
+ return this;
+ case "selectFrame":
+ selectFrame(param1);
+ return this;
+ case "assertElementPresent":
+ assertElementPresent(param1);
+ return this;
+ case "assertElementNotPresent":
+ assertElementNotPresent(param1);
+ return this;
+ case "storeText":
+ storeText(param1, param2);
+ return this;
+ case "storeEval":
+ storeEval(param1, param2);
+ return this;
+ case "store":
+ store(param1, param2);
+ return this;
+ case "assertText":
+ case "waitForText":
+ assertText(param1, param2);
+ return this;
+ case "assertNotText":
+ case "waitForNotText":
+ assertNotText(param1, param2);
+ return this;
+ case "assertTextPresent":
+ assertTextPresent(param1);
+ return this;
+ case "assertTextNotPresent":
+ assertTextNotPresent(param1);
+ return this;
+ case "assertLocation":
+ assertLocation(param1);
+ return this;
+ case "verifyHtmlSource":
+ verifyHtmlSource(param1);
+ return this;
+ case "waitForElementPresent":
+ waitForElementPresent(param1, param2);
+ return this;
+ case "waitForElementNotPresent":
+ waitForElementNotPresent(param1, param2);
+ return this;
+ case "waitForVisible":
+ waitForVisible(param1);
+ return this;
+ case "waitForXpathCount":
+ waitForXpathCount(param1, Integer.parseInt(param2));
+ return this;
+ case "assertValue":
+ case "waitForValue":
+ case "verifyValue":
+ assertInputValue(param1, param2);
+ return this;
+ case "assertConfirmation":
+ confirm(param1);
+ return this;
+ case "setTimeout":
+ case "pause":
+ // Ignore
+ return this;
+ }
+
+ throw new IllegalArgumentException("Unsupported action: " + action);
+ }
+
+ private void open(String url) {
+ if (url.startsWith("/sonar/")) {
+ goTo(url.substring(6));
+ } else {
+ goTo(url);
+ }
+ }
+
+ private void goTo(String url) {
+ requireNonNull(url, "The url cannot be null");
+
+ url = replacePlaceholders(url);
+
+ URI uri = URI.create(url.replace(" ", "%20").replace("|", "%7C"));
+ if (!uri.isAbsolute()) {
+ url = baseUrl + url;
+ }
+
+ System.out.println("goTo " + url);
+ driver.get(url);
+ System.out.println(" - current url " + driver.getCurrentUrl());
+ }
+
+ private LazyDomElement find(String selector) {
+ selector = replacePlaceholders(selector);
+
+ if (selector.startsWith("link=") || selector.startsWith("Link=")) {
+ return find("a").withText(selector.substring(5));
+ }
+
+ By by;
+ if (selector.startsWith("//")) {
+ by = new By.ByXPath(selector);
+ } else if (selector.startsWith("xpath=")) {
+ by = new By.ByXPath(selector.substring(6));
+ } else if (selector.startsWith("id=")) {
+ by = new By.ById(selector.substring(3));
+ } else if (selector.startsWith("name=")) {
+ by = new By.ByName(selector.substring(5));
+ } else if (selector.startsWith("css=")) {
+ by = new By.ByCssSelector(selector.substring(4));
+ } else if (selector.startsWith("class=")) {
+ by = new By.ByCssSelector("." + selector.substring(6));
+ } else {
+ by = new ByCssSelectorOrByNameOrById(selector);
+ }
+
+ return new LazyDomElement(driver, by);
+ }
+
+ private void click(String selector) {
+ find(selector).click();
+ }
+
+ private void check(String selector) {
+ find(selector).check();
+ }
+
+ private void selectFrame(final String id) {
+ if ("relative=parent".equals(id)) {
+ return;
+ }
+
+ System.out.println(" - selectFrame(" + id + ")");
+ _30_SECONDS.execute(new Runnable() {
+ @Override
+ public void run() {
+ driver.switchTo().frame(id);
+ }
+ });
+ }
+
+ private void type(String selector, String text) {
+ find(selector).fill(replacePlaceholders(text));
+ }
+
+ private void keyPressAndWait(String selector, String key) {
+ if (!key.equals("\\13")) {
+ throw new IllegalArgumentException("Invalid key: " + key);
+ }
+ find(selector).pressEnter();
+ }
+
+ private void select(String selector, String text) {
+ if (text.startsWith("label=")) {
+ find(selector).select(text.substring(6));
+ } else {
+ find(selector).select(text);
+ }
+ }
+
+ private void assertElementPresent(String selector) {
+ find(selector).should().beDisplayed();
+ }
+
+ private void assertElementNotPresent(String selector) {
+ find(selector).should().not().beDisplayed();
+ }
+
+ private void storeText(String selector, String name) {
+ find(selector).execute(new ExtractVariable(name));
+ }
+
+ private void storeEval(final String expression, final String name) {
+ // Retry until it's not null and doesn't fail
+ _30_SECONDS.execute(new Runnable() {
+ @Override
+ public void run() {
+ Object result = ((JavascriptExecutor) driver).executeScript("return " + expression);
+ if (result == null) {
+ throw new NotFoundException(expression);
+ }
+ String value = result.toString();
+ variables.put(name, value);
+ }
+ });
+ }
+
+ private void store(String expression, String name) {
+ if (expression.startsWith("javascript{") && expression.endsWith("}")) {
+ storeEval(expression.substring(11, expression.length() - 1), name);
+ } else {
+ throw new IllegalArgumentException("Invalid store expression: " + expression);
+ }
+ }
+
+ private class ExtractVariable implements Consumer<WebElement> {
+ private final String name;
+
+ ExtractVariable(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public void accept(WebElement webElement) {
+ variables.put(name, webElement.getText());
+ }
+
+ public String toString() {
+ return "read value into " + name;
+ }
+ }
+
+ private void assertText(String selector, String pattern) {
+ pattern = replacePlaceholders(pattern);
+
+ if (pattern.startsWith("exact:")) {
+ String expectedText = pattern.substring(6);
+ find(selector).withText(expectedText).should().exist();
+ return;
+ }
+
+ if (pattern.startsWith("regexp:")) {
+ find(selector).should().match(regex(pattern));
+ return;
+ }
+
+ find(selector).should().match(glob(pattern));
+ }
+
+ private void assertNotText(String selector, String pattern) {
+ pattern = replacePlaceholders(pattern);
+
+ if (pattern.startsWith("exact:")) {
+ String expectedText = pattern.substring(6);
+ find(selector).withText(expectedText).should().not().exist();
+ return;
+ }
+
+ if (pattern.startsWith("regexp:")) {
+ find(selector).should().not().match(regex(pattern));
+ return;
+ }
+
+ find(selector).should().not().match(glob(pattern));
+ }
+
+ private static Pattern glob(String pattern) {
+ String regexp = pattern.replaceFirst("glob:", "");
+ regexp = regexp.replaceAll("([\\]\\[\\\\{\\}$\\(\\)\\|\\^\\+.])", "\\\\$1");
+ regexp = regexp.replaceAll("\\*", ".*");
+ regexp = regexp.replaceAll("\\?", ".");
+ return Pattern.compile(regexp, DOTALL | Pattern.CASE_INSENSITIVE);
+ }
+
+ private static Pattern regex(String pattern) {
+ String regexp = pattern.replaceFirst("regexp:", ".*") + ".*";
+ return Pattern.compile(regexp, DOTALL | Pattern.CASE_INSENSITIVE);
+ }
+
+ private void assertTextPresent(String text) {
+ find("body").should().contain(text);
+ }
+
+ private void assertTextNotPresent(String text) {
+ find("body").should().not().contain(text);
+ }
+
+ private void waitForElementPresent(String selector, String text) {
+ if (Strings.isNullOrEmpty(text)) {
+ find(selector).should().exist();
+ } else {
+ find(selector).withText(text).should().exist();
+ }
+ }
+
+ private void waitForElementNotPresent(String selector, String text) {
+ if (Strings.isNullOrEmpty(text)) {
+ find(selector).should().not().exist();
+ } else {
+ find(selector).withText(text).should().not().exist();
+ }
+ }
+
+ private void waitForVisible(String selector) {
+ find(selector).should().beDisplayed();
+ }
+
+ private void assertInputValue(String selector, String text) {
+ find(selector).should().contain(text);
+ }
+
+ private void waitForXpathCount(String selector, int expectedCount) {
+ assertThat(find(selector).stream().size()).isEqualTo(expectedCount);
+ }
+
+ private void confirm(final String message) {
+ System.out.println(" - confirm(" + message + ")");
+
+ _30_SECONDS.execute(new Runnable() {
+ @Override
+ public void run() {
+ driver.switchTo().alert().accept();
+ }
+ });
+ }
+
+ private void assertLocation(String urlPattern) {
+ assertThat(driver.getCurrentUrl()).matches(glob(urlPattern));
+ }
+
+ private void verifyHtmlSource(String expect) {
+ assertThat(driver.getPageSource()).matches(glob(expect));
+ }
+
+ private String replacePlaceholders(String text) {
+ for (Map.Entry<String, String> entry : variables.entrySet()) {
+ text = text.replace("${" + entry.getKey() + "}", entry.getValue());
+ }
+ return text;
+ }
+}