]> source.dussan.org Git - sonarqube.git/commitdiff
Move selenium package to util.selenium package
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 23 Oct 2015 09:17:05 +0000 (11:17 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 27 Oct 2015 20:14:19 +0000 (21:14 +0100)
40 files changed:
it/it-tests/src/test/java/administration/suite/administration/BulkDeletionTest.java
it/it-tests/src/test/java/administration/suite/administration/ProjectAdministrationTest.java
it/it-tests/src/test/java/administration/suite/administration/PropertySetsTest.java
it/it-tests/src/test/java/administration/suite/administration/SubCategoriesTest.java
it/it-tests/src/test/java/administration/suite/ui/I18nTest.java
it/it-tests/src/test/java/analysis/suite/measure/MeasureFiltersTest.java
it/it-tests/src/test/java/issue/suite/ManualRulesTest.java
it/it-tests/src/test/java/qualitygate/QualityGateNotificationTest.java
it/it-tests/src/test/java/selenium/Browser.java [deleted file]
it/it-tests/src/test/java/selenium/ByCssSelectorOrByNameOrById.java [deleted file]
it/it-tests/src/test/java/selenium/Consumer.java [deleted file]
it/it-tests/src/test/java/selenium/ElementFilter.java [deleted file]
it/it-tests/src/test/java/selenium/Failure.java [deleted file]
it/it-tests/src/test/java/selenium/LazyDomElement.java [deleted file]
it/it-tests/src/test/java/selenium/LazyShould.java [deleted file]
it/it-tests/src/test/java/selenium/Optional.java [deleted file]
it/it-tests/src/test/java/selenium/Retry.java [deleted file]
it/it-tests/src/test/java/selenium/SeleneseTest.java [deleted file]
it/it-tests/src/test/java/selenium/SeleniumDriver.java [deleted file]
it/it-tests/src/test/java/selenium/Text.java [deleted file]
it/it-tests/src/test/java/selenium/ThreadSafeDriver.java [deleted file]
it/it-tests/src/test/java/selenium/WebElementHelper.java [deleted file]
it/it-tests/src/test/java/server/ServerTest.java
it/it-tests/src/test/java/server/suite/ServerAdministrationTest.java
it/it-tests/src/test/java/server/suite/ServerTest.java
it/it-tests/src/test/java/updatecenter/UpdateCenterTest.java
it/it-tests/src/test/java/util/selenium/Browser.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/ByCssSelectorOrByNameOrById.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/Consumer.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/ElementFilter.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/Failure.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/LazyDomElement.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/LazyShould.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/Optional.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/Retry.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/SeleneseTest.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/SeleniumDriver.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/Text.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/ThreadSafeDriver.java [new file with mode: 0644]
it/it-tests/src/test/java/util/selenium/WebElementHelper.java [new file with mode: 0644]

index 739ca8394773e892b9c24884a9a262ef598881f4..6d9bea7e3983f803bd88f152396bc696e08a9076 100644 (file)
@@ -26,7 +26,7 @@ import com.sonar.orchestrator.selenium.Selenese;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Test;
-import selenium.SeleneseTest;
+import util.selenium.SeleneseTest;
 
 import static util.ItUtils.projectDir;
 
index 0116963a3bc1680e5bdd5396f04f60bf378bc6b8..d2a73d9fd933f3eb537e10b90e3638236c8610ed 100644 (file)
@@ -42,7 +42,7 @@ import org.sonar.wsclient.qualitygate.UpdateCondition;
 import org.sonar.wsclient.services.PropertyQuery;
 import org.sonar.wsclient.services.ResourceQuery;
 import org.sonar.wsclient.user.UserParameters;
-import selenium.SeleneseTest;
+import util.selenium.SeleneseTest;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static util.ItUtils.projectDir;
index 9d12033afc083d150fbdcfa8d6c6d7c5447fa509..e24b9b08bd036216bbee32a457aa511b7625374e 100644 (file)
@@ -26,7 +26,7 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.sonar.wsclient.services.PropertyQuery;
 import org.sonar.wsclient.services.PropertyUpdateQuery;
-import selenium.SeleneseTest;
+import util.selenium.SeleneseTest;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
index bdaa258983efb3dddb3c106a1963e7f079eb5126..e733108ada076b08a754867d5d8b4072186a35c2 100644 (file)
@@ -26,7 +26,7 @@ import com.sonar.orchestrator.selenium.Selenese;
 import org.junit.ClassRule;
 import org.junit.Test;
 import org.sonar.wsclient.services.PropertyQuery;
-import selenium.SeleneseTest;
+import util.selenium.SeleneseTest;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static util.ItUtils.projectDir;
index 13bd580806658b926ae7ad0b1b201f45c44d8742..ceaae083974c3b00c045c32f21171e364cdc1c30 100644 (file)
@@ -27,7 +27,7 @@ import com.sonar.orchestrator.selenium.Selenese;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Test;
-import selenium.SeleneseTest;
+import util.selenium.SeleneseTest;
 
 import static util.ItUtils.projectDir;
 
index d46717c3065c6265438637624d8f0508cfd72bc4..db4aec15f98986f083c133751bdec290f2b09d8f 100644 (file)
@@ -29,7 +29,7 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.sonar.wsclient.SonarClient;
 import org.sonar.wsclient.user.UserParameters;
-import selenium.SeleneseTest;
+import util.selenium.SeleneseTest;
 
 import static util.ItUtils.projectDir;
 
index 7efb925dcea01ddce3f0a798e407f6127ceadd2a..e7ded7a6f62ccf34d76e78beeecbb326e38c830a 100644 (file)
@@ -27,7 +27,7 @@ import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Test;
-import selenium.SeleneseTest;
+import util.selenium.SeleneseTest;
 
 public class ManualRulesTest {
 
index c2f8450d7d2a923d48f36a03e5995796a7d52b5e..ad6d638dcfa9c3f8fcb395069540d77487f7da83 100644 (file)
@@ -24,8 +24,8 @@ import org.sonar.wsclient.services.Resource;
 import org.sonar.wsclient.services.ResourceQuery;
 import org.subethamail.wiser.Wiser;
 import org.subethamail.wiser.WiserMessage;
-import selenium.SeleneseTest;
 import util.ItUtils;
+import util.selenium.SeleneseTest;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static util.ItUtils.projectDir;
diff --git a/it/it-tests/src/test/java/selenium/Browser.java b/it/it-tests/src/test/java/selenium/Browser.java
deleted file mode 100644 (file)
index 42a98e9..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import org.openqa.selenium.firefox.FirefoxDriver;
-
-public enum Browser {
-  FIREFOX;
-
-  private final ThreadLocal<SeleniumDriver> perThreadDriver = new ThreadLocal<SeleniumDriver>() {
-    @Override
-    protected SeleniumDriver initialValue() {
-      return ThreadSafeDriver.makeThreadSafe(new FirefoxDriver());
-    }
-  };
-
-  public SeleniumDriver getDriverForThread() {
-    return perThreadDriver.get();
-  }
-}
diff --git a/it/it-tests/src/test/java/selenium/ByCssSelectorOrByNameOrById.java b/it/it-tests/src/test/java/selenium/ByCssSelectorOrByNameOrById.java
deleted file mode 100644 (file)
index e510210..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import org.openqa.selenium.By;
-import org.openqa.selenium.SearchContext;
-import org.openqa.selenium.WebElement;
-import org.openqa.selenium.internal.FindsByCssSelector;
-import org.openqa.selenium.internal.FindsById;
-import org.openqa.selenium.internal.FindsByName;
-
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.List;
-
-public class ByCssSelectorOrByNameOrById extends By implements Serializable {
-  private static final long serialVersionUID = -3910258723099459239L;
-
-  private final String selector;
-
-  public ByCssSelectorOrByNameOrById(String selector) {
-    this.selector = selector;
-  }
-
-  @Override
-  public WebElement findElement(SearchContext context) {
-    WebElement element;
-
-    if (validCssSelector(selector)) {
-      element = ((FindsByCssSelector) context).findElementByCssSelector(quoteCss(selector));
-      if (element != null) {
-        return element;
-      }
-    }
-
-    element = ((FindsByName) context).findElementByName(selector);
-    if (element != null) {
-      return element;
-    }
-
-    element = ((FindsById) context).findElementById(selector);
-    if (element != null) {
-      return element;
-    }
-
-    return null;
-  }
-
-  @Override
-  public List<WebElement> findElements(SearchContext context) {
-    List<WebElement> elements;
-
-    if (validCssSelector(selector)) {
-      elements = ((FindsByCssSelector) context).findElementsByCssSelector(quoteCss(selector));
-      if ((elements != null) && (!elements.isEmpty())) {
-        return elements;
-      }
-    }
-
-    elements = ((FindsByName) context).findElementsByName(selector);
-    if ((elements != null) && (!elements.isEmpty())) {
-      return elements;
-    }
-
-    elements = ((FindsById) context).findElementsById(selector);
-    if ((elements != null) && (!elements.isEmpty())) {
-      return elements;
-    }
-
-    return Collections.emptyList();
-  }
-
-  protected boolean validCssSelector(String selector) {
-    return !selector.endsWith("[]");
-  }
-
-  protected String quoteCss(String selector) {
-    if (selector.startsWith(".")) {
-      return selector;
-    }
-    if (selector.startsWith("#")) {
-      return selector.replaceAll("(\\w)[.]", "$1\\\\.");
-    }
-    return selector;
-  }
-
-  @Override
-  public String toString() {
-    return selector;
-  }
-}
diff --git a/it/it-tests/src/test/java/selenium/Consumer.java b/it/it-tests/src/test/java/selenium/Consumer.java
deleted file mode 100644 (file)
index d50e570..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-public interface Consumer<T> {
-  void accept(T t);
-}
diff --git a/it/it-tests/src/test/java/selenium/ElementFilter.java b/it/it-tests/src/test/java/selenium/ElementFilter.java
deleted file mode 100644 (file)
index b4a069a..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import com.google.common.base.Function;
-import org.openqa.selenium.WebElement;
-
-import java.util.Collection;
-
-class ElementFilter {
-  private static final ElementFilter ANY = new ElementFilter("", new Function<Collection<WebElement>, Collection<WebElement>>() {
-    @Override
-    public Collection<WebElement> apply(Collection<WebElement> input) {
-      return input;
-    }
-  });
-
-  private final String description;
-  private final Function<Collection<WebElement>, Collection<WebElement>> filter;
-
-  ElementFilter(String description, Function<Collection<WebElement>, Collection<WebElement>> filter) {
-    this.description = description;
-    this.filter = filter;
-  }
-
-  public String getDescription() {
-    return description;
-  }
-
-  public Function<Collection<WebElement>, Collection<WebElement>> getFilter() {
-    return filter;
-  }
-
-  public static ElementFilter any() {
-    return ANY;
-  }
-
-  public ElementFilter and(final ElementFilter second) {
-    if (ANY == this) {
-      return second;
-    }
-    if (ANY == second) {
-      return this;
-    }
-    return new ElementFilter(description + ',' + second.description, new Function<Collection<WebElement>, Collection<WebElement>>() {
-      @Override
-      public Collection<WebElement> apply(Collection<WebElement> stream) {
-        return second.filter.apply(filter.apply(stream));
-      }
-    });
-  }
-}
diff --git a/it/it-tests/src/test/java/selenium/Failure.java b/it/it-tests/src/test/java/selenium/Failure.java
deleted file mode 100644 (file)
index 2225ebb..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import java.util.ArrayList;
-import java.util.List;
-
-class Failure {
-  private static final String PREFIX = Failure.class.getPackage().getName() + ".";
-
-  private Failure() {
-    // Static class
-  }
-
-  public static AssertionError create(String message) {
-    AssertionError error = new AssertionError(message);
-    removeSimpleleniumFromStackTrace(error);
-    return error;
-  }
-
-  private static void removeSimpleleniumFromStackTrace(Throwable throwable) {
-    List<StackTraceElement> filtered = new ArrayList<>();
-
-    for (StackTraceElement element : throwable.getStackTrace()) {
-      if (!element.getClassName().contains(PREFIX)) {
-        filtered.add(element);
-      }
-    }
-
-    throwable.setStackTrace(filtered.toArray(new StackTraceElement[filtered.size()]));
-  }
-}
diff --git a/it/it-tests/src/test/java/selenium/LazyDomElement.java b/it/it-tests/src/test/java/selenium/LazyDomElement.java
deleted file mode 100644 (file)
index dcf2ee2..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.common.collect.FluentIterable;
-import org.openqa.selenium.By;
-import org.openqa.selenium.Keys;
-import org.openqa.selenium.WebElement;
-import org.openqa.selenium.support.ui.Select;
-
-import javax.annotation.Nullable;
-import java.util.Collection;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-class LazyDomElement {
-  private final SeleniumDriver driver;
-  private final By selector;
-  private final ElementFilter filter;
-  private final Retry retry;
-
-  LazyDomElement(SeleniumDriver driver, By selector) {
-    this(driver, selector, Retry._30_SECONDS);
-  }
-
-  LazyDomElement(SeleniumDriver driver, By selector, Retry retry) {
-    this(driver, selector, ElementFilter.any(), retry);
-  }
-
-  private LazyDomElement(SeleniumDriver driver, By selector, ElementFilter filter, Retry retry) {
-    this.driver = driver;
-    this.selector = selector;
-    this.filter = filter;
-    this.retry = retry;
-  }
-
-  public LazyDomElement withText(final String text) {
-    String fullDescription = " with text [" + text + "]";
-
-    return with(new ElementFilter(fullDescription, new Function<Collection<WebElement>, Collection<WebElement>>() {
-      @Override
-      public Collection<WebElement> apply(Collection<WebElement> stream) {
-        return FluentIterable.from(stream).filter(new Predicate<WebElement>() {
-          @Override
-          public boolean apply(@Nullable WebElement element) {
-//            return Objects.equals(element.getText(), text);
-            return element.getText().contains(text);
-          }
-        }).toList();
-      }
-    }));
-  }
-
-  public LazyShould should() {
-    return new LazyShould(this, Retry._30_SECONDS, true);
-  }
-
-  public void fill(final CharSequence text) {
-    execute("fill(" + text + ")", new Consumer<WebElement>() {
-      @Override
-      public void accept(WebElement element) {
-        element.clear();
-        element.sendKeys(text);
-      }
-    });
-  }
-
-  public void pressEnter() {
-    execute("pressEnter", new Consumer<WebElement>() {
-      @Override
-      public void accept(WebElement element) {
-        element.sendKeys(Keys.ENTER);
-      }
-    });
-  }
-
-  public void select(final String text) {
-    executeSelect("select(" + text + ")", new Consumer<Select>() {
-      @Override
-      public void accept(Select select) {
-        select.selectByVisibleText(text);
-      }
-    });
-  }
-
-  public void executeSelect(String description, final Consumer<Select> selectOnElement) {
-    execute(description, new Consumer<WebElement>() {
-      @Override
-      public void accept(WebElement element) {
-        selectOnElement.accept(new Select(element));
-      }
-    });
-  }
-
-  public void click() {
-    execute("click", new Consumer<WebElement>() {
-      @Override
-      public void accept(WebElement element) {
-        element.click();
-      }
-    });
-  }
-
-  public void check() {
-    execute("check", new Consumer<WebElement>() {
-      @Override
-      public void accept(WebElement element) {
-        if (!element.isSelected()) {
-          element.click();
-        }
-      }
-    });
-  }
-
-  public void execute(Consumer<WebElement> action) {
-    execute("execute(" + action + ")", action);
-  }
-
-  private LazyDomElement with(ElementFilter filter) {
-    return new LazyDomElement(driver, selector, this.filter.and(filter), retry);
-  }
-
-  private void execute(String message, Consumer<WebElement> action) {
-    System.out.println(" - " + Text.toString(selector) + filter.getDescription() + "." + message);
-
-    Supplier<Optional<WebElement>> findOne = new Supplier<Optional<WebElement>>() {
-      @Override
-      public Optional<WebElement> get() {
-        List<WebElement> elements = stream();
-        if (elements.isEmpty()) {
-          return Optional.empty();
-        }
-        return Optional.of(elements.get(0));
-      }
-    };
-
-    try {
-      retry.execute(findOne, action);
-    } catch (NoSuchElementException e) {
-      throw new AssertionError("Element not found: " + Text.toString(selector));
-    }
-  }
-
-  List<WebElement> stream() {
-    return FluentIterable.from(filter.getFilter().apply(driver.findElements(selector))).toList();
-  }
-
-  @Override
-  public String toString() {
-    return Text.toString(selector) + filter.getDescription();
-  }
-}
\ No newline at end of file
diff --git a/it/it-tests/src/test/java/selenium/LazyShould.java b/it/it-tests/src/test/java/selenium/LazyShould.java
deleted file mode 100644 (file)
index c344ba7..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import com.google.common.base.*;
-import com.google.common.collect.FluentIterable;
-import org.openqa.selenium.WebElement;
-
-import javax.annotation.Nullable;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.regex.Pattern;
-
-import static selenium.Text.plural;
-import static selenium.WebElementHelper.text;
-
-class LazyShould {
-  private final LazyDomElement element;
-  private final Retry retry;
-  private final boolean ok;
-
-  LazyShould(LazyDomElement element, Retry retry, boolean ok) {
-    this.element = element;
-    this.retry = retry;
-    this.ok = ok;
-  }
-
-  public LazyShould beDisplayed() {
-    return verify(
-      isOrNot("displayed"),
-      new Predicate<List<WebElement>>() {
-        @Override
-        public boolean apply(List<WebElement> elements) {
-          return !elements.isEmpty() && FluentIterable.from(elements).allMatch(new Predicate<WebElement>() {
-            @Override
-            public boolean apply(WebElement element) {
-              return element.isDisplayed();
-            }
-          });
-        }
-      },
-      new Function<List<WebElement>, String>() {
-        @Override
-        public String apply(List<WebElement> elements) {
-          return "It is " + statuses(elements, new Function<WebElement, String>() {
-            @Override
-            public String apply(WebElement element) {
-              return displayedStatus(element);
-            }
-          });
-        }
-      });
-  }
-
-  public LazyShould match(final Pattern regexp) {
-    return verify(
-      doesOrNot("match") + " (" + regexp.pattern() + ")",
-      new Predicate<List<WebElement>>() {
-        @Override
-        public boolean apply(List<WebElement> elements) {
-          return !elements.isEmpty() && FluentIterable.from(elements).anyMatch(new Predicate<WebElement>() {
-            @Override
-            public boolean apply(WebElement element) {
-              return regexp.matcher(text(element)).matches();
-            }
-          });
-        }
-      },
-      new Function<List<WebElement>, String>() {
-        @Override
-        public String apply(List<WebElement> elements) {
-          return "It contains " + statuses(elements, new Function<WebElement, String>() {
-            @Nullable
-            @Override
-            public String apply(@Nullable WebElement element) {
-              return text(element);
-            }
-          });
-        }
-      });
-  }
-
-  public LazyShould contain(final String text) {
-    return verify(
-      doesOrNot("contain") + "(" + text + ")",
-      new Predicate<List<WebElement>>() {
-        @Override
-        public boolean apply(List<WebElement> elements) {
-          return FluentIterable.from(elements).anyMatch(new Predicate<WebElement>() {
-            @Override
-            public boolean apply(@Nullable WebElement element) {
-              if (text.startsWith("exact:")) {
-                return text(element).equals(text.substring(6));
-              }
-              return text(element).contains(text);
-            }
-          });
-        }
-      },
-      new Function<List<WebElement>, String>() {
-        @Override
-        public String apply(List<WebElement> elements) {
-          return "It contains " + statuses(elements, new Function<WebElement, String>() {
-            @Override
-            public String apply(WebElement element) {
-              return text(element);
-            }
-          });
-        }
-      });
-  }
-
-  public LazyShould exist() {
-    return verify(
-      doesOrNot("exist"),
-      new Predicate<List<WebElement>>() {
-        @Override
-        public boolean apply(List<WebElement> elements) {
-          return !elements.isEmpty();
-        }
-      },
-      new Function<List<WebElement>, String>() {
-        @Override
-        public String apply(List<WebElement> elements) {
-          return "It contains " + plural(elements.size(), "element");
-        }
-      });
-  }
-
-  private static String displayedStatus(WebElement element) {
-    return element.isDisplayed() ? "displayed" : "not displayed";
-  }
-
-  private LazyShould verify(String message, Predicate<List<WebElement>> predicate, Function<List<WebElement>, String> toErrorMessage) {
-    String verification = "verify that " + element + " " + message;
-    System.out.println("   -> " + verification);
-
-    try {
-      if (!retry.verify(new Supplier<List<WebElement>>() {
-        @Override
-        public List<WebElement> get() {
-          return LazyShould.this.findElements();
-        }
-      }, ok ? predicate : Predicates.not(predicate))) {
-        throw Failure.create("Failed to " + verification + ". " + toErrorMessage.apply(findElements()));
-      }
-    } catch (NoSuchElementException e) {
-      throw Failure.create("Element not found. Failed to " + verification);
-    }
-
-    return ok ? this : not();
-  }
-
-  private List<WebElement> findElements() {
-    return element.stream();
-  }
-
-  private static String statuses(List<WebElement> elements, Function<WebElement, String> toStatus) {
-    return "(" + FluentIterable.from(elements).transform(toStatus).join(Joiner.on(";")) + ")";
-  }
-
-  public LazyShould not() {
-    return new LazyShould(element, retry, !ok);
-  }
-
-  private String doesOrNot(String verb) {
-    return Text.doesOrNot(!ok, verb);
-  }
-
-  private String isOrNot(String state) {
-    return Text.isOrNot(!ok, state);
-  }
-}
diff --git a/it/it-tests/src/test/java/selenium/Optional.java b/it/it-tests/src/test/java/selenium/Optional.java
deleted file mode 100644 (file)
index ed4b626..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import java.util.NoSuchElementException;
-
-public final class Optional<T> {
-  private static final Optional<?> EMPTY = new Optional<>();
-
-  private final T value;
-
-  private Optional() {
-    this.value = null;
-  }
-
-  public static <T> Optional<T> empty() {
-    @SuppressWarnings("unchecked")
-    Optional<T> t = (Optional<T>) EMPTY;
-    return t;
-  }
-
-  private Optional(T value) {
-    this.value = value;
-  }
-
-  public static <T> Optional<T> of(T value) {
-    return new Optional<>(value);
-  }
-
-  public T get() {
-    if (value == null) {
-      throw new NoSuchElementException("No value present");
-    }
-    return value;
-  }
-
-  public boolean isPresent() {
-    return value != null;
-  }
-}
diff --git a/it/it-tests/src/test/java/selenium/Retry.java b/it/it-tests/src/test/java/selenium/Retry.java
deleted file mode 100644 (file)
index cc13823..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import org.openqa.selenium.InvalidElementStateException;
-import org.openqa.selenium.NotFoundException;
-import org.openqa.selenium.StaleElementReferenceException;
-import org.openqa.selenium.WebDriverException;
-
-import java.util.NoSuchElementException;
-import java.util.concurrent.TimeUnit;
-
-import static java.util.concurrent.TimeUnit.SECONDS;
-
-class Retry {
-  public static final Retry _30_SECONDS = new Retry(30, SECONDS);
-
-  private final long timeoutInMs;
-
-  Retry(long duration, TimeUnit timeUnit) {
-    this.timeoutInMs = timeUnit.toMillis(duration);
-  }
-
-  <T> void execute(Supplier<Optional<T>> target, Consumer<T> action) {
-    WebDriverException lastError = null;
-
-    boolean retried = false;
-
-    long start = System.currentTimeMillis();
-    while ((System.currentTimeMillis() - start) < timeoutInMs) {
-      try {
-        Optional<T> targetElement = target.get();
-        if (targetElement.isPresent()) {
-          action.accept(targetElement.get());
-          if (retried) {
-            System.out.println();
-          }
-          return;
-        }
-      } catch (StaleElementReferenceException e) {
-        // ignore
-      } catch (WebDriverException e) {
-        lastError = e;
-      }
-
-      retried = true;
-      System.out.print(".");
-    }
-
-    if (retried) {
-      System.out.println();
-    }
-
-    if (lastError != null) {
-      throw lastError;
-    }
-    throw new NoSuchElementException("Not found");
-  }
-
-  <T> void execute(Runnable action) {
-    WebDriverException lastError = null;
-
-    boolean retried = false;
-
-    long start = System.currentTimeMillis();
-    while ((System.currentTimeMillis() - start) < timeoutInMs) {
-      try {
-        action.run();
-        if (retried) {
-          System.out.println();
-        }
-        return;
-      } catch (StaleElementReferenceException e) {
-        // ignore
-      } catch (WebDriverException e) {
-        lastError = e;
-      }
-
-      retried = true;
-      System.out.print(".");
-    }
-
-    if (retried) {
-      System.out.println();
-    }
-
-    if (lastError != null) {
-      throw lastError;
-    }
-    throw new NoSuchElementException("Not found");
-  }
-
-  <T> boolean verify(Supplier<T> targetSupplier, Predicate<T> predicate) throws NoSuchElementException {
-    Error error = Error.KO;
-
-    boolean retried = false;
-
-    long start = System.currentTimeMillis();
-    while ((System.currentTimeMillis() - start) < timeoutInMs) {
-      try {
-        if (predicate.apply(targetSupplier.get())) {
-          if (retried) {
-            System.out.println();
-          }
-          return true;
-        }
-
-        error = Error.KO;
-      } catch (InvalidElementStateException e) {
-        error = Error.KO;
-      } catch (NotFoundException e) {
-        error = Error.NOT_FOUND;
-      } catch (StaleElementReferenceException e) {
-        // ignore
-      }
-
-      retried = true;
-      System.out.print(".");
-    }
-
-    if (retried) {
-      System.out.println();
-    }
-
-    if (error == Error.NOT_FOUND) {
-      throw new NoSuchElementException("Not found");
-    }
-    return false;
-  }
-
-  enum Error {
-    NOT_FOUND, KO
-  }
-}
diff --git a/it/it-tests/src/test/java/selenium/SeleneseTest.java b/it/it-tests/src/test/java/selenium/SeleneseTest.java
deleted file mode 100644 (file)
index 1c5de94..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.selenium.Selenese;
-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.NotFoundException;
-import org.openqa.selenium.WebElement;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-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 selenium.Retry._30_SECONDS;
-
-public class SeleneseTest {
-  private final Selenese suite;
-
-  private Map<String, String> variables;
-  private String baseUrl;
-  private SeleniumDriver driver;
-
-  public SeleneseTest(Selenese suite) {
-    this.suite = suite;
-  }
-
-  public void runOn(Orchestrator orchestrator) {
-    this.variables = new HashMap<>();
-    this.baseUrl = orchestrator.getServer().getUrl();
-    this.driver = Browser.FIREFOX.getDriverForThread();
-
-    driver.manage().deleteAllCookies();
-
-    for (File file : suite.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();
-
-            action(action, param1, param2);
-          }
-        }
-      }
-    }
-  }
-
-  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 SeleneseTest 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 "waitForElementPresent":
-        waitForElementPresent(param1, param2);
-        return this;
-      case "waitForVisible":
-        waitForVisible(param1);
-        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"));
-    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 = 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 waitForVisible(String selector) {
-    find(selector).should().beDisplayed();
-  }
-
-  private void assertInputValue(String selector, String text) {
-    find(selector).should().contain(text);
-  }
-
-  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 String replacePlaceholders(String text) {
-    for (Map.Entry<String, String> entry : variables.entrySet()) {
-      text = text.replace("${" + entry.getKey() + "}", entry.getValue());
-    }
-    return text;
-  }
-}
diff --git a/it/it-tests/src/test/java/selenium/SeleniumDriver.java b/it/it-tests/src/test/java/selenium/SeleniumDriver.java
deleted file mode 100644 (file)
index 7a60acf..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-public interface SeleniumDriver extends org.openqa.selenium.WebDriver, org.openqa.selenium.JavascriptExecutor, org.openqa.selenium.internal.FindsById, org.openqa.selenium.internal.FindsByClassName, org.openqa.selenium.internal.FindsByLinkText, org.openqa.selenium.internal.FindsByName, org.openqa.selenium.internal.FindsByCssSelector, org.openqa.selenium.internal.FindsByTagName, org.openqa.selenium.internal.FindsByXPath, org.openqa.selenium.interactions.HasInputDevices, org.openqa.selenium.HasCapabilities, org.openqa.selenium.TakesScreenshot {
-}
diff --git a/it/it-tests/src/test/java/selenium/Text.java b/it/it-tests/src/test/java/selenium/Text.java
deleted file mode 100644 (file)
index aba0f42..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import com.google.common.base.Joiner;
-import org.openqa.selenium.By;
-
-public abstract class Text {
-  private Text() {
-    // Static utility class
-  }
-
-  public static String doesOrNot(boolean not, String verb) {
-    if (!verb.contains(" ")) {
-      if (not) {
-        return "doesn't " + verb;
-      } else if (verb.endsWith("h")) {
-        return verb + "es";
-      } else {
-        return verb + "s";
-      }
-    }
-
-    String[] verbs = verb.split(" ");
-    verbs[0] = doesOrNot(not, verbs[0]);
-
-    return Joiner.on(" ").join(verbs);
-  }
-
-  public static String isOrNot(boolean not, String state) {
-    return (not ? "is not " : "is ") + state;
-  }
-
-  public static String plural(int n, String word) {
-    return (n + " " + word) + (n <= 1 ? "" : "s");
-  }
-
-  public static String toString(By selector) {
-    return selector.toString().replace("By.selector: ", "").replace("By.cssSelector: ", "");
-  }
-}
diff --git a/it/it-tests/src/test/java/selenium/ThreadSafeDriver.java b/it/it-tests/src/test/java/selenium/ThreadSafeDriver.java
deleted file mode 100644 (file)
index 1f507cb..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import org.openqa.selenium.remote.RemoteWebDriver;
-import org.openqa.selenium.remote.UnreachableBrowserException;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-class ThreadSafeDriver {
-  private ThreadSafeDriver() {
-    // Static class
-  }
-
-  static SeleniumDriver makeThreadSafe(final RemoteWebDriver driver) {
-    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          driver.quit();
-        } catch (UnreachableBrowserException e) {
-          // Ignore. The browser was killed properly
-        }
-      }
-    }));
-
-    return (SeleniumDriver) Proxy.newProxyInstance(
-      Thread.currentThread().getContextClassLoader(),
-      findInterfaces(driver),
-      new InvocationHandler() {
-        @Override
-        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-          if (method.getName().equals("quit")) {
-            return null; // We don't want anybody to quit() our (per thread) driver
-          }
-
-          try {
-            return method.invoke(driver, args);
-          } catch (InvocationTargetException e) {
-            throw e.getCause();
-          }
-        }
-      });
-  }
-
-  private static Class[] findInterfaces(Object driver) {
-    Set<Class<?>> interfaces = new LinkedHashSet<>();
-
-    interfaces.add(SeleniumDriver.class);
-
-    for (Class<?> parent = driver.getClass(); parent != null; ) {
-      Collections.addAll(interfaces, parent.getInterfaces());
-      parent = parent.getSuperclass();
-    }
-
-    return interfaces.toArray(new Class[interfaces.size()]);
-  }
-}
\ No newline at end of file
diff --git a/it/it-tests/src/test/java/selenium/WebElementHelper.java b/it/it-tests/src/test/java/selenium/WebElementHelper.java
deleted file mode 100644 (file)
index 0d7a8ed..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 selenium;
-
-import org.openqa.selenium.WebElement;
-
-class WebElementHelper {
-  WebElementHelper() {
-    // Static class
-  }
-
-  public static String text(WebElement element) {
-    String text = element.getText();
-    if (!"".equals(text)) {
-      return nullToEmpty(text);
-    }
-
-    return nullToEmpty(element.getAttribute("value"));
-  }
-
-  private static String nullToEmpty(String text) {
-    return (text == null) ? "" : text;
-  }
-}
index 95a2956ed977f992ef55e061a3d97dd18b20f429..9c4bc9719398b795813369c282bcb1629543ab90 100644 (file)
@@ -19,8 +19,8 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.wsclient.services.Server;
 import org.sonar.wsclient.services.ServerQuery;
-import selenium.SeleneseTest;
 import util.ItUtils;
+import util.selenium.SeleneseTest;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.fail;
index 617899891d09558e313efc9c8ad5131b8072f6e4..b2d85d657c246c121b880e321ba119d5d59c2cb3 100644 (file)
@@ -22,7 +22,7 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.sonar.wsclient.services.Server;
 import org.sonar.wsclient.services.ServerQuery;
-import selenium.SeleneseTest;
+import util.selenium.SeleneseTest;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.fail;
index 57ab6c3b33f14664c7c97026bcf962a44048b1d4..27a2aeab267a3b29e47aba1e7a8e786a9b30886e 100644 (file)
@@ -23,8 +23,8 @@ import org.junit.rules.ExpectedException;
 import org.sonar.wsclient.base.HttpException;
 import org.sonar.wsclient.services.PropertyDeleteQuery;
 import org.sonar.wsclient.services.PropertyUpdateQuery;
-import selenium.SeleneseTest;
 import util.ItUtils;
+import util.selenium.SeleneseTest;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
index d42907bfb8535c36968b38076f7ab70abb4e1065..790883b9e34e8c27f54699ade30373906203117a 100644 (file)
@@ -13,7 +13,7 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.sonar.wsclient.services.Plugin;
 import org.sonar.wsclient.services.UpdateCenterQuery;
-import selenium.SeleneseTest;
+import util.selenium.SeleneseTest;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static util.ItUtils.pluginArtifact;
diff --git a/it/it-tests/src/test/java/util/selenium/Browser.java b/it/it-tests/src/test/java/util/selenium/Browser.java
new file mode 100644 (file)
index 0000000..8d687f6
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 org.openqa.selenium.firefox.FirefoxDriver;
+
+public enum Browser {
+  FIREFOX;
+
+  private final ThreadLocal<SeleniumDriver> perThreadDriver = new ThreadLocal<SeleniumDriver>() {
+    @Override
+    protected SeleniumDriver initialValue() {
+      return ThreadSafeDriver.makeThreadSafe(new FirefoxDriver());
+    }
+  };
+
+  public SeleniumDriver getDriverForThread() {
+    return perThreadDriver.get();
+  }
+}
diff --git a/it/it-tests/src/test/java/util/selenium/ByCssSelectorOrByNameOrById.java b/it/it-tests/src/test/java/util/selenium/ByCssSelectorOrByNameOrById.java
new file mode 100644 (file)
index 0000000..8edc9ef
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import org.openqa.selenium.By;
+import org.openqa.selenium.SearchContext;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.internal.FindsByCssSelector;
+import org.openqa.selenium.internal.FindsById;
+import org.openqa.selenium.internal.FindsByName;
+
+public class ByCssSelectorOrByNameOrById extends By implements Serializable {
+  private static final long serialVersionUID = -3910258723099459239L;
+
+  private final String selector;
+
+  public ByCssSelectorOrByNameOrById(String selector) {
+    this.selector = selector;
+  }
+
+  @Override
+  public WebElement findElement(SearchContext context) {
+    WebElement element;
+
+    if (validCssSelector(selector)) {
+      element = ((FindsByCssSelector) context).findElementByCssSelector(quoteCss(selector));
+      if (element != null) {
+        return element;
+      }
+    }
+
+    element = ((FindsByName) context).findElementByName(selector);
+    if (element != null) {
+      return element;
+    }
+
+    element = ((FindsById) context).findElementById(selector);
+    if (element != null) {
+      return element;
+    }
+
+    return null;
+  }
+
+  @Override
+  public List<WebElement> findElements(SearchContext context) {
+    List<WebElement> elements;
+
+    if (validCssSelector(selector)) {
+      elements = ((FindsByCssSelector) context).findElementsByCssSelector(quoteCss(selector));
+      if ((elements != null) && (!elements.isEmpty())) {
+        return elements;
+      }
+    }
+
+    elements = ((FindsByName) context).findElementsByName(selector);
+    if ((elements != null) && (!elements.isEmpty())) {
+      return elements;
+    }
+
+    elements = ((FindsById) context).findElementsById(selector);
+    if ((elements != null) && (!elements.isEmpty())) {
+      return elements;
+    }
+
+    return Collections.emptyList();
+  }
+
+  protected boolean validCssSelector(String selector) {
+    return !selector.endsWith("[]");
+  }
+
+  protected String quoteCss(String selector) {
+    if (selector.startsWith(".")) {
+      return selector;
+    }
+    if (selector.startsWith("#")) {
+      return selector.replaceAll("(\\w)[.]", "$1\\\\.");
+    }
+    return selector;
+  }
+
+  @Override
+  public String toString() {
+    return selector;
+  }
+}
diff --git a/it/it-tests/src/test/java/util/selenium/Consumer.java b/it/it-tests/src/test/java/util/selenium/Consumer.java
new file mode 100644 (file)
index 0000000..4bdee4b
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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;
+
+public interface Consumer<T> {
+  void accept(T t);
+}
diff --git a/it/it-tests/src/test/java/util/selenium/ElementFilter.java b/it/it-tests/src/test/java/util/selenium/ElementFilter.java
new file mode 100644 (file)
index 0000000..cad64ee
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.google.common.base.Function;
+import java.util.Collection;
+import org.openqa.selenium.WebElement;
+
+class ElementFilter {
+  private static final ElementFilter ANY = new ElementFilter("", new Function<Collection<WebElement>, Collection<WebElement>>() {
+    @Override
+    public Collection<WebElement> apply(Collection<WebElement> input) {
+      return input;
+    }
+  });
+
+  private final String description;
+  private final Function<Collection<WebElement>, Collection<WebElement>> filter;
+
+  ElementFilter(String description, Function<Collection<WebElement>, Collection<WebElement>> filter) {
+    this.description = description;
+    this.filter = filter;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public Function<Collection<WebElement>, Collection<WebElement>> getFilter() {
+    return filter;
+  }
+
+  public static ElementFilter any() {
+    return ANY;
+  }
+
+  public ElementFilter and(final ElementFilter second) {
+    if (ANY == this) {
+      return second;
+    }
+    if (ANY == second) {
+      return this;
+    }
+    return new ElementFilter(description + ',' + second.description, new Function<Collection<WebElement>, Collection<WebElement>>() {
+      @Override
+      public Collection<WebElement> apply(Collection<WebElement> stream) {
+        return second.filter.apply(filter.apply(stream));
+      }
+    });
+  }
+}
diff --git a/it/it-tests/src/test/java/util/selenium/Failure.java b/it/it-tests/src/test/java/util/selenium/Failure.java
new file mode 100644 (file)
index 0000000..d4b4ba2
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 java.util.ArrayList;
+import java.util.List;
+
+class Failure {
+  private static final String PREFIX = Failure.class.getPackage().getName() + ".";
+
+  private Failure() {
+    // Static class
+  }
+
+  public static AssertionError create(String message) {
+    AssertionError error = new AssertionError(message);
+    removeSimpleleniumFromStackTrace(error);
+    return error;
+  }
+
+  private static void removeSimpleleniumFromStackTrace(Throwable throwable) {
+    List<StackTraceElement> filtered = new ArrayList<>();
+
+    for (StackTraceElement element : throwable.getStackTrace()) {
+      if (!element.getClassName().contains(PREFIX)) {
+        filtered.add(element);
+      }
+    }
+
+    throwable.setStackTrace(filtered.toArray(new StackTraceElement[filtered.size()]));
+  }
+}
diff --git a/it/it-tests/src/test/java/util/selenium/LazyDomElement.java b/it/it-tests/src/test/java/util/selenium/LazyDomElement.java
new file mode 100644 (file)
index 0000000..cdaf402
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.FluentIterable;
+import java.util.Collection;
+import java.util.List;
+import java.util.NoSuchElementException;
+import javax.annotation.Nullable;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.Select;
+
+class LazyDomElement {
+  private final SeleniumDriver driver;
+  private final By selector;
+  private final ElementFilter filter;
+  private final Retry retry;
+
+  LazyDomElement(SeleniumDriver driver, By selector) {
+    this(driver, selector, Retry._30_SECONDS);
+  }
+
+  LazyDomElement(SeleniumDriver driver, By selector, Retry retry) {
+    this(driver, selector, ElementFilter.any(), retry);
+  }
+
+  private LazyDomElement(SeleniumDriver driver, By selector, ElementFilter filter, Retry retry) {
+    this.driver = driver;
+    this.selector = selector;
+    this.filter = filter;
+    this.retry = retry;
+  }
+
+  public LazyDomElement withText(final String text) {
+    String fullDescription = " with text [" + text + "]";
+
+    return with(new ElementFilter(fullDescription, new Function<Collection<WebElement>, Collection<WebElement>>() {
+      @Override
+      public Collection<WebElement> apply(Collection<WebElement> stream) {
+        return FluentIterable.from(stream).filter(new Predicate<WebElement>() {
+          @Override
+          public boolean apply(@Nullable WebElement element) {
+//            return Objects.equals(element.getText(), text);
+            return element.getText().contains(text);
+          }
+        }).toList();
+      }
+    }));
+  }
+
+  public LazyShould should() {
+    return new LazyShould(this, Retry._30_SECONDS, true);
+  }
+
+  public void fill(final CharSequence text) {
+    execute("fill(" + text + ")", new Consumer<WebElement>() {
+      @Override
+      public void accept(WebElement element) {
+        element.clear();
+        element.sendKeys(text);
+      }
+    });
+  }
+
+  public void pressEnter() {
+    execute("pressEnter", new Consumer<WebElement>() {
+      @Override
+      public void accept(WebElement element) {
+        element.sendKeys(Keys.ENTER);
+      }
+    });
+  }
+
+  public void select(final String text) {
+    executeSelect("select(" + text + ")", new Consumer<Select>() {
+      @Override
+      public void accept(Select select) {
+        select.selectByVisibleText(text);
+      }
+    });
+  }
+
+  public void executeSelect(String description, final Consumer<Select> selectOnElement) {
+    execute(description, new Consumer<WebElement>() {
+      @Override
+      public void accept(WebElement element) {
+        selectOnElement.accept(new Select(element));
+      }
+    });
+  }
+
+  public void click() {
+    execute("click", new Consumer<WebElement>() {
+      @Override
+      public void accept(WebElement element) {
+        element.click();
+      }
+    });
+  }
+
+  public void check() {
+    execute("check", new Consumer<WebElement>() {
+      @Override
+      public void accept(WebElement element) {
+        if (!element.isSelected()) {
+          element.click();
+        }
+      }
+    });
+  }
+
+  public void execute(Consumer<WebElement> action) {
+    execute("execute(" + action + ")", action);
+  }
+
+  private LazyDomElement with(ElementFilter filter) {
+    return new LazyDomElement(driver, selector, this.filter.and(filter), retry);
+  }
+
+  private void execute(String message, Consumer<WebElement> action) {
+    System.out.println(" - " + Text.toString(selector) + filter.getDescription() + "." + message);
+
+    Supplier<Optional<WebElement>> findOne = new Supplier<Optional<WebElement>>() {
+      @Override
+      public Optional<WebElement> get() {
+        List<WebElement> elements = stream();
+        if (elements.isEmpty()) {
+          return Optional.empty();
+        }
+        return Optional.of(elements.get(0));
+      }
+    };
+
+    try {
+      retry.execute(findOne, action);
+    } catch (NoSuchElementException e) {
+      throw new AssertionError("Element not found: " + Text.toString(selector));
+    }
+  }
+
+  List<WebElement> stream() {
+    return FluentIterable.from(filter.getFilter().apply(driver.findElements(selector))).toList();
+  }
+
+  @Override
+  public String toString() {
+    return Text.toString(selector) + filter.getDescription();
+  }
+}
diff --git a/it/it-tests/src/test/java/util/selenium/LazyShould.java b/it/it-tests/src/test/java/util/selenium/LazyShould.java
new file mode 100644 (file)
index 0000000..17a5f39
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
+import com.google.common.collect.FluentIterable;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.regex.Pattern;
+import javax.annotation.Nullable;
+import org.openqa.selenium.WebElement;
+
+class LazyShould {
+  private final LazyDomElement element;
+  private final Retry retry;
+  private final boolean ok;
+
+  LazyShould(LazyDomElement element, Retry retry, boolean ok) {
+    this.element = element;
+    this.retry = retry;
+    this.ok = ok;
+  }
+
+  public LazyShould beDisplayed() {
+    return verify(
+      isOrNot("displayed"),
+      new Predicate<List<WebElement>>() {
+        @Override
+        public boolean apply(List<WebElement> elements) {
+          return !elements.isEmpty() && FluentIterable.from(elements).allMatch(new Predicate<WebElement>() {
+            @Override
+            public boolean apply(WebElement element) {
+              return element.isDisplayed();
+            }
+          });
+        }
+      },
+      new Function<List<WebElement>, String>() {
+        @Override
+        public String apply(List<WebElement> elements) {
+          return "It is " + statuses(elements, new Function<WebElement, String>() {
+            @Override
+            public String apply(WebElement element) {
+              return displayedStatus(element);
+            }
+          });
+        }
+      });
+  }
+
+  public LazyShould match(final Pattern regexp) {
+    return verify(
+      doesOrNot("match") + " (" + regexp.pattern() + ")",
+      new Predicate<List<WebElement>>() {
+        @Override
+        public boolean apply(List<WebElement> elements) {
+          return !elements.isEmpty() && FluentIterable.from(elements).anyMatch(new Predicate<WebElement>() {
+            @Override
+            public boolean apply(WebElement element) {
+              return regexp.matcher(WebElementHelper.text(element)).matches();
+            }
+          });
+        }
+      },
+      new Function<List<WebElement>, String>() {
+        @Override
+        public String apply(List<WebElement> elements) {
+          return "It contains " + statuses(elements, new Function<WebElement, String>() {
+            @Nullable
+            @Override
+            public String apply(@Nullable WebElement element) {
+              return WebElementHelper.text(element);
+            }
+          });
+        }
+      });
+  }
+
+  public LazyShould contain(final String text) {
+    return verify(
+      doesOrNot("contain") + "(" + text + ")",
+      new Predicate<List<WebElement>>() {
+        @Override
+        public boolean apply(List<WebElement> elements) {
+          return FluentIterable.from(elements).anyMatch(new Predicate<WebElement>() {
+            @Override
+            public boolean apply(@Nullable WebElement element) {
+              if (text.startsWith("exact:")) {
+                return WebElementHelper.text(element).equals(text.substring(6));
+              }
+              return WebElementHelper.text(element).contains(text);
+            }
+          });
+        }
+      },
+      new Function<List<WebElement>, String>() {
+        @Override
+        public String apply(List<WebElement> elements) {
+          return "It contains " + statuses(elements, new Function<WebElement, String>() {
+            @Override
+            public String apply(WebElement element) {
+              return WebElementHelper.text(element);
+            }
+          });
+        }
+      });
+  }
+
+  public LazyShould exist() {
+    return verify(
+      doesOrNot("exist"),
+      new Predicate<List<WebElement>>() {
+        @Override
+        public boolean apply(List<WebElement> elements) {
+          return !elements.isEmpty();
+        }
+      },
+      new Function<List<WebElement>, String>() {
+        @Override
+        public String apply(List<WebElement> elements) {
+          return "It contains " + Text.plural(elements.size(), "element");
+        }
+      });
+  }
+
+  private static String displayedStatus(WebElement element) {
+    return element.isDisplayed() ? "displayed" : "not displayed";
+  }
+
+  private LazyShould verify(String message, Predicate<List<WebElement>> predicate, Function<List<WebElement>, String> toErrorMessage) {
+    String verification = "verify that " + element + " " + message;
+    System.out.println("   -> " + verification);
+
+    try {
+      if (!retry.verify(new Supplier<List<WebElement>>() {
+        @Override
+        public List<WebElement> get() {
+          return LazyShould.this.findElements();
+        }
+      }, ok ? predicate : Predicates.not(predicate))) {
+        throw Failure.create("Failed to " + verification + ". " + toErrorMessage.apply(findElements()));
+      }
+    } catch (NoSuchElementException e) {
+      throw Failure.create("Element not found. Failed to " + verification);
+    }
+
+    return ok ? this : not();
+  }
+
+  private List<WebElement> findElements() {
+    return element.stream();
+  }
+
+  private static String statuses(List<WebElement> elements, Function<WebElement, String> toStatus) {
+    return "(" + FluentIterable.from(elements).transform(toStatus).join(Joiner.on(";")) + ")";
+  }
+
+  public LazyShould not() {
+    return new LazyShould(element, retry, !ok);
+  }
+
+  private String doesOrNot(String verb) {
+    return Text.doesOrNot(!ok, verb);
+  }
+
+  private String isOrNot(String state) {
+    return Text.isOrNot(!ok, state);
+  }
+}
diff --git a/it/it-tests/src/test/java/util/selenium/Optional.java b/it/it-tests/src/test/java/util/selenium/Optional.java
new file mode 100644 (file)
index 0000000..35d97a0
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 java.util.NoSuchElementException;
+
+public final class Optional<T> {
+  private static final Optional<?> EMPTY = new Optional<>();
+
+  private final T value;
+
+  private Optional() {
+    this.value = null;
+  }
+
+  public static <T> Optional<T> empty() {
+    @SuppressWarnings("unchecked")
+    Optional<T> t = (Optional<T>) EMPTY;
+    return t;
+  }
+
+  private Optional(T value) {
+    this.value = value;
+  }
+
+  public static <T> Optional<T> of(T value) {
+    return new Optional<>(value);
+  }
+
+  public T get() {
+    if (value == null) {
+      throw new NoSuchElementException("No value present");
+    }
+    return value;
+  }
+
+  public boolean isPresent() {
+    return value != null;
+  }
+}
diff --git a/it/it-tests/src/test/java/util/selenium/Retry.java b/it/it-tests/src/test/java/util/selenium/Retry.java
new file mode 100644 (file)
index 0000000..089642c
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import java.util.NoSuchElementException;
+import java.util.concurrent.TimeUnit;
+import org.openqa.selenium.InvalidElementStateException;
+import org.openqa.selenium.NotFoundException;
+import org.openqa.selenium.StaleElementReferenceException;
+import org.openqa.selenium.WebDriverException;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+class Retry {
+  public static final Retry _30_SECONDS = new Retry(30, SECONDS);
+
+  private final long timeoutInMs;
+
+  Retry(long duration, TimeUnit timeUnit) {
+    this.timeoutInMs = timeUnit.toMillis(duration);
+  }
+
+  <T> void execute(Supplier<Optional<T>> target, Consumer<T> action) {
+    WebDriverException lastError = null;
+
+    boolean retried = false;
+
+    long start = System.currentTimeMillis();
+    while ((System.currentTimeMillis() - start) < timeoutInMs) {
+      try {
+        Optional<T> targetElement = target.get();
+        if (targetElement.isPresent()) {
+          action.accept(targetElement.get());
+          if (retried) {
+            System.out.println();
+          }
+          return;
+        }
+      } catch (StaleElementReferenceException e) {
+        // ignore
+      } catch (WebDriverException e) {
+        lastError = e;
+      }
+
+      retried = true;
+      System.out.print(".");
+    }
+
+    if (retried) {
+      System.out.println();
+    }
+
+    if (lastError != null) {
+      throw lastError;
+    }
+    throw new NoSuchElementException("Not found");
+  }
+
+  <T> void execute(Runnable action) {
+    WebDriverException lastError = null;
+
+    boolean retried = false;
+
+    long start = System.currentTimeMillis();
+    while ((System.currentTimeMillis() - start) < timeoutInMs) {
+      try {
+        action.run();
+        if (retried) {
+          System.out.println();
+        }
+        return;
+      } catch (StaleElementReferenceException e) {
+        // ignore
+      } catch (WebDriverException e) {
+        lastError = e;
+      }
+
+      retried = true;
+      System.out.print(".");
+    }
+
+    if (retried) {
+      System.out.println();
+    }
+
+    if (lastError != null) {
+      throw lastError;
+    }
+    throw new NoSuchElementException("Not found");
+  }
+
+  <T> boolean verify(Supplier<T> targetSupplier, Predicate<T> predicate) throws NoSuchElementException {
+    Error error = Error.KO;
+
+    boolean retried = false;
+
+    long start = System.currentTimeMillis();
+    while ((System.currentTimeMillis() - start) < timeoutInMs) {
+      try {
+        if (predicate.apply(targetSupplier.get())) {
+          if (retried) {
+            System.out.println();
+          }
+          return true;
+        }
+
+        error = Error.KO;
+      } catch (InvalidElementStateException e) {
+        error = Error.KO;
+      } catch (NotFoundException e) {
+        error = Error.NOT_FOUND;
+      } catch (StaleElementReferenceException e) {
+        // ignore
+      }
+
+      retried = true;
+      System.out.print(".");
+    }
+
+    if (retried) {
+      System.out.println();
+    }
+
+    if (error == Error.NOT_FOUND) {
+      throw new NoSuchElementException("Not found");
+    }
+    return false;
+  }
+
+  enum Error {
+    NOT_FOUND, KO
+  }
+}
diff --git a/it/it-tests/src/test/java/util/selenium/SeleneseTest.java b/it/it-tests/src/test/java/util/selenium/SeleneseTest.java
new file mode 100644 (file)
index 0000000..51e3371
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 com.sonar.orchestrator.selenium.Selenese;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+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.NotFoundException;
+import org.openqa.selenium.WebElement;
+
+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;
+
+public class SeleneseTest {
+  private final Selenese suite;
+
+  private Map<String, String> variables;
+  private String baseUrl;
+  private SeleniumDriver driver;
+
+  public SeleneseTest(Selenese suite) {
+    this.suite = suite;
+  }
+
+  public void runOn(Orchestrator orchestrator) {
+    this.variables = new HashMap<>();
+    this.baseUrl = orchestrator.getServer().getUrl();
+    this.driver = Browser.FIREFOX.getDriverForThread();
+
+    driver.manage().deleteAllCookies();
+
+    for (File file : suite.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();
+
+            action(action, param1, param2);
+          }
+        }
+      }
+    }
+  }
+
+  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 SeleneseTest 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 "waitForElementPresent":
+        waitForElementPresent(param1, param2);
+        return this;
+      case "waitForVisible":
+        waitForVisible(param1);
+        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"));
+    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 = 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 waitForVisible(String selector) {
+    find(selector).should().beDisplayed();
+  }
+
+  private void assertInputValue(String selector, String text) {
+    find(selector).should().contain(text);
+  }
+
+  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 String replacePlaceholders(String text) {
+    for (Map.Entry<String, String> entry : variables.entrySet()) {
+      text = text.replace("${" + entry.getKey() + "}", entry.getValue());
+    }
+    return text;
+  }
+}
diff --git a/it/it-tests/src/test/java/util/selenium/SeleniumDriver.java b/it/it-tests/src/test/java/util/selenium/SeleniumDriver.java
new file mode 100644 (file)
index 0000000..5b0392a
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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;
+
+public interface SeleniumDriver extends org.openqa.selenium.WebDriver, org.openqa.selenium.JavascriptExecutor, org.openqa.selenium.internal.FindsById, org.openqa.selenium.internal.FindsByClassName, org.openqa.selenium.internal.FindsByLinkText, org.openqa.selenium.internal.FindsByName, org.openqa.selenium.internal.FindsByCssSelector, org.openqa.selenium.internal.FindsByTagName, org.openqa.selenium.internal.FindsByXPath, org.openqa.selenium.interactions.HasInputDevices, org.openqa.selenium.HasCapabilities, org.openqa.selenium.TakesScreenshot {
+}
diff --git a/it/it-tests/src/test/java/util/selenium/Text.java b/it/it-tests/src/test/java/util/selenium/Text.java
new file mode 100644 (file)
index 0000000..2dba5cb
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.google.common.base.Joiner;
+import org.openqa.selenium.By;
+
+public abstract class Text {
+  private Text() {
+    // Static utility class
+  }
+
+  public static String doesOrNot(boolean not, String verb) {
+    if (!verb.contains(" ")) {
+      if (not) {
+        return "doesn't " + verb;
+      } else if (verb.endsWith("h")) {
+        return verb + "es";
+      } else {
+        return verb + "s";
+      }
+    }
+
+    String[] verbs = verb.split(" ");
+    verbs[0] = doesOrNot(not, verbs[0]);
+
+    return Joiner.on(" ").join(verbs);
+  }
+
+  public static String isOrNot(boolean not, String state) {
+    return (not ? "is not " : "is ") + state;
+  }
+
+  public static String plural(int n, String word) {
+    return (n + " " + word) + (n <= 1 ? "" : "s");
+  }
+
+  public static String toString(By selector) {
+    return selector.toString().replace("By.selector: ", "").replace("By.cssSelector: ", "");
+  }
+}
diff --git a/it/it-tests/src/test/java/util/selenium/ThreadSafeDriver.java b/it/it-tests/src/test/java/util/selenium/ThreadSafeDriver.java
new file mode 100644 (file)
index 0000000..abe92e4
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import org.openqa.selenium.remote.RemoteWebDriver;
+import org.openqa.selenium.remote.UnreachableBrowserException;
+
+class ThreadSafeDriver {
+  private ThreadSafeDriver() {
+    // Static class
+  }
+
+  static SeleniumDriver makeThreadSafe(final RemoteWebDriver driver) {
+    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          driver.quit();
+        } catch (UnreachableBrowserException e) {
+          // Ignore. The browser was killed properly
+        }
+      }
+    }));
+
+    return (SeleniumDriver) Proxy.newProxyInstance(
+      Thread.currentThread().getContextClassLoader(),
+      findInterfaces(driver),
+      new InvocationHandler() {
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+          if (method.getName().equals("quit")) {
+            return null; // We don't want anybody to quit() our (per thread) driver
+          }
+
+          try {
+            return method.invoke(driver, args);
+          } catch (InvocationTargetException e) {
+            throw e.getCause();
+          }
+        }
+      });
+  }
+
+  private static Class[] findInterfaces(Object driver) {
+    Set<Class<?>> interfaces = new LinkedHashSet<>();
+
+    interfaces.add(SeleniumDriver.class);
+
+    for (Class<?> parent = driver.getClass(); parent != null; ) {
+      Collections.addAll(interfaces, parent.getInterfaces());
+      parent = parent.getSuperclass();
+    }
+
+    return interfaces.toArray(new Class[interfaces.size()]);
+  }
+}
diff --git a/it/it-tests/src/test/java/util/selenium/WebElementHelper.java b/it/it-tests/src/test/java/util/selenium/WebElementHelper.java
new file mode 100644 (file)
index 0000000..99ef6cf
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 org.openqa.selenium.WebElement;
+
+class WebElementHelper {
+  WebElementHelper() {
+    // Static class
+  }
+
+  public static String text(WebElement element) {
+    String text = element.getText();
+    if (!"".equals(text)) {
+      return nullToEmpty(text);
+    }
+
+    return nullToEmpty(element.getAttribute("value"));
+  }
+
+  private static String nullToEmpty(String text) {
+    return (text == null) ? "" : text;
+  }
+}