diff options
author | David Gageot <david@gageot.net> | 2015-08-31 15:01:41 +0200 |
---|---|---|
committer | David Gageot <david@gageot.net> | 2015-09-02 13:02:17 +0200 |
commit | 60fc38d183e03e7f50253b5c28ad1261da3d3b4b (patch) | |
tree | f7225b91cb6978de99b863a1cf648ce47b879a19 /it | |
parent | 01830ed40953d22b634f0a6fb7a6c220d5b5de67 (diff) | |
download | sonarqube-60fc38d183e03e7f50253b5c28ad1261da3d3b4b.tar.gz sonarqube-60fc38d183e03e7f50253b5c28ad1261da3d3b4b.zip |
Give a Try to a better? selenium framework
Diffstat (limited to 'it')
30 files changed, 1219 insertions, 47 deletions
diff --git a/it/it-tests/pom.xml b/it/it-tests/pom.xml index 9e4ce6383ee..3e67e663662 100644 --- a/it/it-tests/pom.xml +++ b/it/it-tests/pom.xml @@ -81,7 +81,11 @@ <artifactId>jsonassert</artifactId> <version>1.2.0</version> </dependency> - + <dependency> + <groupId>org.jsoup</groupId> + <artifactId>jsoup</artifactId> + <version>1.8.3</version> + </dependency> <!-- Email notifications --> <dependency> diff --git a/it/it-tests/src/test/java/administration/suite/administration/BulkDeletionTest.java b/it/it-tests/src/test/java/administration/suite/administration/BulkDeletionTest.java index a833589cb60..4ee932e5d67 100644 --- a/it/it-tests/src/test/java/administration/suite/administration/BulkDeletionTest.java +++ b/it/it-tests/src/test/java/administration/suite/administration/BulkDeletionTest.java @@ -26,6 +26,7 @@ import com.sonar.orchestrator.selenium.Selenese; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; +import selenium.SeleneseTest; import static util.ItUtils.projectDir; @@ -52,7 +53,7 @@ public class BulkDeletionTest { Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("project-bulk-deletion-on-selected-project", "/administration/suite/BulkDeletionTest/project-bulk-deletion/bulk-delete-filter-projects.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } /** @@ -67,7 +68,7 @@ public class BulkDeletionTest { "/administration/suite/BulkDeletionTest/project-bulk-deletion/display-two-letters-long-project.html", "/administration/suite/BulkDeletionTest/project-bulk-deletion/filter-two-letters-long-project.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } private void executeBuild(String projectKey, String projectName) { diff --git a/it/it-tests/src/test/java/administration/suite/administration/ProjectAdministrationTest.java b/it/it-tests/src/test/java/administration/suite/administration/ProjectAdministrationTest.java index 62d624c58a7..939b2af95a5 100644 --- a/it/it-tests/src/test/java/administration/suite/administration/ProjectAdministrationTest.java +++ b/it/it-tests/src/test/java/administration/suite/administration/ProjectAdministrationTest.java @@ -43,6 +43,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 static org.assertj.core.api.Assertions.assertThat; import static util.ItUtils.projectDir; @@ -116,9 +117,10 @@ public class ProjectAdministrationTest { adminClient.permissionClient().addPermission( PermissionParameters.create().user(projectAdminUser).component("sample").permission("admin")); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese( Selenese.builder().setHtmlTestsInClasspath("project-deletion", "/administration/suite/ProjectAdministrationTest/project-deletion/project-deletion.html").build() - ); + ); } finally { adminClient.userClient().deactivate(projectAdminUser); } @@ -141,21 +143,19 @@ public class ProjectAdministrationTest { // There are 7 modules assertThat(count("events where category='Version'")).as("Different number of events").isEqualTo(7); - Selenese selenese = Selenese - .builder() + Selenese selenese = Selenese.builder() .setHtmlTestsInClasspath("modify_version_of_multimodule_project", "/administration/suite/ProjectAdministrationTest/project-administration/multimodule-project-modify-version.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); assertThat(count("events where category='Version'")).as("Different number of events").isEqualTo(14); - selenese = Selenese - .builder() + selenese = Selenese.builder() .setHtmlTestsInClasspath("delete_version_of_multimodule_project", "/administration/suite/ProjectAdministrationTest/project-administration/multimodule-project-delete-version.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); assertThat(count("events where category='Version'")).as("Different number of events").isEqualTo(7); } @@ -174,11 +174,11 @@ public class ProjectAdministrationTest { qgClient.updateCondition(UpdateCondition.create(lowThresholds.id()).metricKey("lines").operator("GT").warningThreshold("5000").errorThreshold("5000")); scanSampleWithDate("2012-01-02"); - Selenese selenese = Selenese - .builder() + Selenese selenese = Selenese.builder() .setHtmlTestsInClasspath("display-alerts-history-page", "/administration/suite/ProjectAdministrationTest/display-alerts-history-page/should-display-alerts-correctly-history-page.html" ).build(); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(selenese); qgClient.unsetDefault(); @@ -202,12 +202,11 @@ public class ProjectAdministrationTest { // Red alert because lines number has not changed since previous analysis scanSample(); - Selenese selenese = Selenese - .builder() + Selenese selenese = Selenese.builder() .setHtmlTestsInClasspath("display-period-alerts", "/administration/suite/ProjectAdministrationTest/display-alerts/should-display-period-alerts-correctly.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); qgClient.unsetDefault(); qgClient.destroy(qGate.id()); @@ -226,7 +225,7 @@ public class ProjectAdministrationTest { "/administration/suite/ProjectAdministrationTest/project-settings/only-on-project-settings.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); assertThat(orchestrator.getServer().getAdminWsClient().find(PropertyQuery.createForResource("sonar.skippedModules", "sample")).getValue()) .isEqualTo("my-excluded-module"); @@ -240,14 +239,14 @@ public class ProjectAdministrationTest { SonarRunner build = SonarRunner.create(projectDir("shared/xoo-multi-modules-sample")); orchestrator.executeBuild(build); - Selenese selenese = Selenese - .builder() + Selenese selenese = Selenese.builder() .setHtmlTestsInClasspath("project-bulk-update-keys", "/administration/suite/ProjectAdministrationTest/project-update-keys/bulk-update-impossible-because-duplicate-keys.html", "/administration/suite/ProjectAdministrationTest/project-update-keys/bulk-update-impossible-because-no-input.html", "/administration/suite/ProjectAdministrationTest/project-update-keys/bulk-update-impossible-because-no-match.html", "/administration/suite/ProjectAdministrationTest/project-update-keys/bulk-update-success.html" ).build(); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(selenese); } @@ -259,12 +258,12 @@ public class ProjectAdministrationTest { SonarRunner build = SonarRunner.create(projectDir("shared/xoo-multi-modules-sample")); orchestrator.executeBuild(build); - Selenese selenese = Selenese - .builder() + Selenese selenese = Selenese.builder() .setHtmlTestsInClasspath("project-fine-grained-update-keys", "/administration/suite/ProjectAdministrationTest/project-update-keys/fine-grained-update-impossible.html", "/administration/suite/ProjectAdministrationTest/project-update-keys/fine-grained-update-success.html" ).build(); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(selenese); } @@ -279,7 +278,7 @@ public class ProjectAdministrationTest { // SONAR-3425 "/administration/suite/ProjectAdministrationTest/module-settings/display-module-settings.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } private void scanSample() { diff --git a/it/it-tests/src/test/java/administration/suite/administration/PropertySetsTest.java b/it/it-tests/src/test/java/administration/suite/administration/PropertySetsTest.java index 0dc2573cc7f..9d12033afc0 100644 --- a/it/it-tests/src/test/java/administration/suite/administration/PropertySetsTest.java +++ b/it/it-tests/src/test/java/administration/suite/administration/PropertySetsTest.java @@ -26,6 +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 static org.assertj.core.api.Assertions.assertThat; @@ -42,6 +43,7 @@ public class PropertySetsTest { "/administration/suite/PropertySetsTest/property-sets/reference.html", "/administration/suite/PropertySetsTest/property-sets/all_types.html" ).build(); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(selenese); // SSF-25 Check that the password has well be setted as now it does not appears in the html source code @@ -66,18 +68,19 @@ public class PropertySetsTest { @Test public void should_support_property_sets_with_auto_generated_keys() { - orchestrator.executeSelenese(Selenese.builder().setHtmlTestsInClasspath("create-auto-generated", + new SeleneseTest( + Selenese.builder().setHtmlTestsInClasspath("create-auto-generated", "/administration/suite/PropertySetsTest/auto-generated/create.html" - ).build()); + ).build()).runOn(orchestrator); String[] keys = getProperty("sonar.autogenerated").split("[,]"); assertThat(getProperty("sonar.autogenerated." + keys[0] + ".value")).isEqualTo("FIRST"); assertThat(getProperty("sonar.autogenerated." + keys[1] + ".value")).isEqualTo("SECOND"); assertThat(getProperty("sonar.autogenerated." + keys[2] + ".value")).isEqualTo("THIRD"); - orchestrator.executeSelenese(Selenese.builder().setHtmlTestsInClasspath("update-auto-generated", + new SeleneseTest(Selenese.builder().setHtmlTestsInClasspath("update-auto-generated", "/administration/suite/PropertySetsTest/auto-generated/update.html" - ).build()); + ).build()).runOn(orchestrator); keys = getProperty("sonar.autogenerated").split("[,]"); assertThat(getProperty("sonar.autogenerated." + keys[0] + ".value")).isEqualTo("FIRST"); diff --git a/it/it-tests/src/test/java/administration/suite/administration/SubCategoriesTest.java b/it/it-tests/src/test/java/administration/suite/administration/SubCategoriesTest.java index e54541e5f28..bdaa258983e 100644 --- a/it/it-tests/src/test/java/administration/suite/administration/SubCategoriesTest.java +++ b/it/it-tests/src/test/java/administration/suite/administration/SubCategoriesTest.java @@ -26,6 +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 static org.assertj.core.api.Assertions.assertThat; import static util.ItUtils.projectDir; @@ -45,7 +46,7 @@ public class SubCategoriesTest { // SONAR-4495 "/administration/suite/SubCategoriesTest/subcategories/global-subcategories-no-default.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); assertThat(getProperty("prop3", null)).isEqualTo("myValue"); } @@ -61,7 +62,7 @@ public class SubCategoriesTest { // SONAR-4495 "/administration/suite/SubCategoriesTest/subcategories/project-subcategories-no-default.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); assertThat(getProperty("prop3", "sample")).isEqualTo("myValue2"); } diff --git a/it/it-tests/src/test/java/administration/suite/ui/I18nTest.java b/it/it-tests/src/test/java/administration/suite/ui/I18nTest.java index b0e9dc4d820..14a9ec84f4d 100644 --- a/it/it-tests/src/test/java/administration/suite/ui/I18nTest.java +++ b/it/it-tests/src/test/java/administration/suite/ui/I18nTest.java @@ -53,6 +53,7 @@ public class I18nTest { "/ui/i18n/french-pack.html", "/ui/i18n/locale-with-france-country.html", "/ui/i18n/locale-with-swiss-country.html").build(); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(selenese); } diff --git a/it/it-tests/src/test/java/analysis/suite/measure/MeasureFiltersTest.java b/it/it-tests/src/test/java/analysis/suite/measure/MeasureFiltersTest.java index bae341a805a..b699beaba3b 100644 --- a/it/it-tests/src/test/java/analysis/suite/measure/MeasureFiltersTest.java +++ b/it/it-tests/src/test/java/analysis/suite/measure/MeasureFiltersTest.java @@ -63,6 +63,7 @@ public class MeasureFiltersTest { "/measure/suite/measure_filters/search-by-name.html", "/measure/suite/measure_filters/empty_filter.html" ).build(); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(selenese); } @@ -75,6 +76,7 @@ public class MeasureFiltersTest { "/measure/suite/measure_filters/list_sort_by_descending_name.html", "/measure/suite/measure_filters/list_sort_by_ncloc.html" ).build(); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(selenese); } @@ -89,6 +91,7 @@ public class MeasureFiltersTest { // SONAR-4469 "/measure/suite/measure_filters/should-unshare-filter-remove-other-filters-favourite.html" ).build(); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(selenese); } finally { @@ -105,6 +108,7 @@ public class MeasureFiltersTest { createUser(user, "User Measure Filters without sharing permission"); try { + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(Selenese.builder().setHtmlTestsInClasspath("should_not_share_filter_when_user_have_no_sharing_permissions", "/measure/suite/measure_filters/should-not-share-filter-when-user-have-no-sharing-permissions.html" ).build()); @@ -119,6 +123,7 @@ public class MeasureFiltersTest { "/measure/suite/measure_filters/copy_measure_filter.html", "/measure/suite/measure_filters/copy_uniqueness_of_name.html" ).build(); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(selenese); } @@ -127,6 +132,7 @@ public class MeasureFiltersTest { Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("manage_measure_filters", "/measure/suite/measure_filters/save_with_special_characters.html" ).build(); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(selenese); } @@ -137,6 +143,7 @@ public class MeasureFiltersTest { "/measure/suite/measure_filters/list_widget_sort.html", "/measure/suite/measure_filters/list_widget_warning_if_missing_filter.html" ).build(); + // Use the old runner because it fails with the new Selenium runner orchestrator.executeSelenese(selenese); } diff --git a/it/it-tests/src/test/java/issue/suite/ManualRulesTest.java b/it/it-tests/src/test/java/issue/suite/ManualRulesTest.java index 506c6493bf0..aa986112501 100644 --- a/it/it-tests/src/test/java/issue/suite/ManualRulesTest.java +++ b/it/it-tests/src/test/java/issue/suite/ManualRulesTest.java @@ -13,6 +13,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; +import selenium.SeleneseTest; public class ManualRulesTest { @@ -37,7 +38,7 @@ public class ManualRulesTest { .setHtmlTestsInClasspath("manual-rules", "/issue/suite/ManualRulesTest/create_edit_delete_manual_rule.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } protected static void deleteManualRules(){ diff --git a/it/it-tests/src/test/java/qualitygate/QualityGateNotificationTest.java b/it/it-tests/src/test/java/qualitygate/QualityGateNotificationTest.java index 70467aeb4d8..c2f8450d7d2 100644 --- a/it/it-tests/src/test/java/qualitygate/QualityGateNotificationTest.java +++ b/it/it-tests/src/test/java/qualitygate/QualityGateNotificationTest.java @@ -24,6 +24,7 @@ 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 static org.assertj.core.api.Assertions.assertThat; @@ -64,7 +65,7 @@ public class QualityGateNotificationTest { .setHtmlTestsInClasspath("notifications", "/qualitygate/notifications/email_configuration.html", "/qualitygate/notifications/activate_notification_channels.html").build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); // Create quality gate with conditions on variations QualityGate simple = qgClient().create("SimpleWithDifferential"); diff --git a/it/it-tests/src/test/java/selenium/Browser.java b/it/it-tests/src/test/java/selenium/Browser.java new file mode 100644 index 00000000000..2a6e02eb03a --- /dev/null +++ b/it/it-tests/src/test/java/selenium/Browser.java @@ -0,0 +1,18 @@ +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 new file mode 100644 index 00000000000..7a4d8dd1016 --- /dev/null +++ b/it/it-tests/src/test/java/selenium/ByCssSelectorOrByNameOrById.java @@ -0,0 +1,89 @@ +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 new file mode 100644 index 00000000000..f6dfad9bccd --- /dev/null +++ b/it/it-tests/src/test/java/selenium/Consumer.java @@ -0,0 +1,5 @@ +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 new file mode 100644 index 00000000000..2816a3a871d --- /dev/null +++ b/it/it-tests/src/test/java/selenium/ElementFilter.java @@ -0,0 +1,50 @@ +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 new file mode 100644 index 00000000000..c7794904b9f --- /dev/null +++ b/it/it-tests/src/test/java/selenium/Failure.java @@ -0,0 +1,30 @@ +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 new file mode 100644 index 00000000000..0c0d18d0bac --- /dev/null +++ b/it/it-tests/src/test/java/selenium/LazyDomElement.java @@ -0,0 +1,143 @@ +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.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._5_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 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 new file mode 100644 index 00000000000..71891df2b78 --- /dev/null +++ b/it/it-tests/src/test/java/selenium/LazyShould.java @@ -0,0 +1,171 @@ +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 new file mode 100644 index 00000000000..3a8ced04e6c --- /dev/null +++ b/it/it-tests/src/test/java/selenium/Optional.java @@ -0,0 +1,38 @@ +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 new file mode 100644 index 00000000000..b559f62b473 --- /dev/null +++ b/it/it-tests/src/test/java/selenium/Retry.java @@ -0,0 +1,135 @@ +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); + public static final Retry _5_SECONDS = new Retry(5, 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 new file mode 100644 index 00000000000..ecd716775fc --- /dev/null +++ b/it/it-tests/src/test/java/selenium/SeleneseTest.java @@ -0,0 +1,349 @@ +package selenium; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.selenium.Selenese; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.openqa.selenium.Alert; +import org.openqa.selenium.By; +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 org.assertj.core.api.Assertions.assertThat; + +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(); + + 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 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, param2); + return this; + case "type": + type(param1, param2); + return this; + case "select": + select(param1, param2); + return this; + case "clickAndWait": + case "click": + click(param1, param2); + return this; + case "check": + check(param1, param2); + return this; + case "selectFrame": + selectFrame(param1, param2); + return this; + case "assertElementPresent": + assertElementPresent(param1, param2); + return this; + case "assertElementNotPresent": + assertElementNotPresent(param1, param2); + return this; + case "storeText": + storeText(param1, param2); + return this; + case "storeEval": + storeEval(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, param2); + case "assertTextNotPresent": + assertTextNotPresent(param1, param2); + return this; + case "assertLocation": + assertLocation(param1, param2); + return this; + case "waitForElementPresent": + waitForElementPresent(param1, param2); + return this; + case "waitForVisible": + waitForVisible(param1, param2); + return this; + case "assertValue": + case "waitForValue": + case "verifyValue": + assertInputValue(param1, param2); + return this; + case "assertConfirmation": + confirm(param1, param2); + return this; + case "setTimeout": + // Ignore + return this; + } + + throw new IllegalArgumentException("Unsupported action: " + action); + } + + private void goTo(String url) { + requireNonNull(url, "The url cannot be null"); + + 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 void open(String url, String ignored) { + if (url.startsWith("/sonar/")) { + goTo(url.substring(6)); + } else { + goTo(url); + } + } + + private LazyDomElement find(String selector) { + selector = replacePlaceholders(selector); + + if (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 { + by = new ByCssSelectorOrByNameOrById(cleanUp(selector)); + } + + return new LazyDomElement(driver, by); + } + + private void click(String selector, String ignored) { + find(selector).click(); + } + + private void check(String selector, String ignored) { + find(selector).check(); + } + + private void selectFrame(final String id, String ignored) { + if ("relative=parent".equals(id)) { + //driver().switchTo().parentFrame(); + } else { + System.out.println(" - selectFrame(" + id + ")"); + + Retry._5_SECONDS.execute(new Runnable() { + @Override + public void run() { + driver.switchTo().frame(id); + } + }); + } + } + + private String cleanUp(String selector) { + if (selector.startsWith("name=")) { + return selector.substring(5); + } + if (selector.startsWith("css=")) { + return selector.substring(4); + } + if (selector.startsWith("id=")) { + return "#" + selector.substring(3); + } + if (selector.startsWith("class=")) { + return "." + selector.substring(6); + } + return selector; + } + + private void type(String selector, String text) { + find(selector).fill(replacePlaceholders(text)); + } + + 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, String ignored) { + find(selector).should().beDisplayed(); + } + + private void assertElementNotPresent(String selector, String ignored) { + find(selector).should().not().beDisplayed(); + } + + private void storeText(String selector, String name) { + find(selector).execute(new ExtractVariable(name)); + } + + private void storeEval(String expression, String name) { + String value = driver.executeScript("return " + expression).toString(); + variables.put(name, value); + } + + 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(Pattern.compile(pattern.substring(7))); + 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(Pattern.compile(pattern.substring(7))); + return; + } + + find(selector).should().not().match(glob(pattern)); + } + + private Pattern glob(String pattern) { + String expectedGlob = pattern.replaceFirst("glob:", ""); + expectedGlob = expectedGlob.replaceAll("([\\]\\[\\\\{\\}$\\(\\)\\|\\^\\+.])", "\\\\$1"); + expectedGlob = expectedGlob.replaceAll("\\*", ".*"); + expectedGlob = expectedGlob.replaceAll("\\?", "."); + return Pattern.compile(expectedGlob, Pattern.DOTALL); + } + + private void assertTextPresent(String text, String ignored) { + find("html").should().contain(text); + } + + private void assertTextNotPresent(String text, String ignored) { + find("html").should().not().contain(text); + } + + private void waitForElementPresent(String selector, String ignored) { + find(selector).should().exist(); + } + + private void waitForVisible(String selector, String ignored) { + find(selector).should().beDisplayed(); + } + + private void assertInputValue(String selector, String text) { + find(selector).should().contain(text); + } + + private void confirm(final String message, String ignored) { + System.out.println(" - confirm(" + message + ")"); + + Retry._5_SECONDS.execute(new Runnable() { + @Override + public void run() { + Alert alert = driver.switchTo().alert(); + if (alert.getText().contains(message)) { + alert.accept(); + } + } + }); + } + + private void assertLocation(String urlPattern, String ignored) { + 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 new file mode 100644 index 00000000000..cd215663a2b --- /dev/null +++ b/it/it-tests/src/test/java/selenium/SeleniumDriver.java @@ -0,0 +1,4 @@ +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 new file mode 100644 index 00000000000..76dfd43f8b2 --- /dev/null +++ b/it/it-tests/src/test/java/selenium/Text.java @@ -0,0 +1,39 @@ +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 new file mode 100644 index 00000000000..96c16e21fff --- /dev/null +++ b/it/it-tests/src/test/java/selenium/ThreadSafeDriver.java @@ -0,0 +1,62 @@ +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 new file mode 100644 index 00000000000..82935d7ca6a --- /dev/null +++ b/it/it-tests/src/test/java/selenium/WebElementHelper.java @@ -0,0 +1,22 @@ +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; + } +} diff --git a/it/it-tests/src/test/java/server/ServerTest.java b/it/it-tests/src/test/java/server/ServerTest.java index acaffab22ee..23ac3c27c34 100644 --- a/it/it-tests/src/test/java/server/ServerTest.java +++ b/it/it-tests/src/test/java/server/ServerTest.java @@ -19,6 +19,7 @@ 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 static org.assertj.core.api.Assertions.assertThat; @@ -70,7 +71,7 @@ public class ServerTest { // SONAR-3127 - hide passwords "/server/ServerTest/settings/hide-passwords.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } @Test @@ -92,7 +93,7 @@ public class ServerTest { Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("property_relocation", "/server/ServerTest/settings/property_relocation.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } /** diff --git a/it/it-tests/src/test/java/server/suite/ServerAdministrationTest.java b/it/it-tests/src/test/java/server/suite/ServerAdministrationTest.java index a0c042c9f18..617899891d0 100644 --- a/it/it-tests/src/test/java/server/suite/ServerAdministrationTest.java +++ b/it/it-tests/src/test/java/server/suite/ServerAdministrationTest.java @@ -22,6 +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 static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; @@ -51,7 +52,7 @@ public class ServerAdministrationTest { // SONAR-4102 "/server/ServerAdministrationTest/server_id/organisation_must_not_accept_special_chars.html", "/server/ServerAdministrationTest/server_id/valid_id.html").build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } @Test @@ -59,7 +60,7 @@ public class ServerAdministrationTest { Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("server-administration", "/server/ServerAdministrationTest/server-administration/system_info.html" ).build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } /** @@ -91,7 +92,7 @@ public class ServerAdministrationTest { * SONAR-5197 */ @Test - public void api_ws_shortcut() throws IOException { + public void api_ws_shortcut() throws Exception { HttpClient httpclient = new DefaultHttpClient(); try { HttpGet get = new HttpGet(orchestrator.getServer().getUrl() + "/api"); diff --git a/it/it-tests/src/test/java/server/suite/ServerTest.java b/it/it-tests/src/test/java/server/suite/ServerTest.java index 725dbf7dddb..57ab6c3b33f 100644 --- a/it/it-tests/src/test/java/server/suite/ServerTest.java +++ b/it/it-tests/src/test/java/server/suite/ServerTest.java @@ -23,6 +23,7 @@ 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 static org.assertj.core.api.Assertions.assertThat; @@ -48,7 +49,7 @@ public class ServerTest { if (orchestrator.getConfiguration().getString("sonar.jdbc.dialect").equals("h2")) { Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("derby-warnings", "/server/ServerTest/derby-warning.html").build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } } @@ -59,7 +60,7 @@ public class ServerTest { public void hide_jdbc_settings_to_non_admin() { Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("jdbc-settings", "/server/ServerTest/hide-jdbc-settings.html").build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } /** @@ -125,7 +126,7 @@ public class ServerTest { // Access dashboard Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("url_ending_by_jsp", "/server/ServerTest/url_ending_by_jsp.html").build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } // SONAR-4404 @@ -133,7 +134,7 @@ public class ServerTest { public void should_get_settings_default_value() { Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("settings-default-value", "/server/ServerTest/settings-default-value.html").build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } } diff --git a/it/it-tests/src/test/java/updatecenter/UpdateCenterTest.java b/it/it-tests/src/test/java/updatecenter/UpdateCenterTest.java index 373f337b2ec..d42907bfb85 100644 --- a/it/it-tests/src/test/java/updatecenter/UpdateCenterTest.java +++ b/it/it-tests/src/test/java/updatecenter/UpdateCenterTest.java @@ -13,6 +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 static org.assertj.core.api.Assertions.assertThat; import static util.ItUtils.pluginArtifact; @@ -42,7 +43,7 @@ public class UpdateCenterTest { Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("server-update-center", "/updatecenter/installed-plugins.html") .build(); - orchestrator.executeSelenese(selenese); + new SeleneseTest(selenese).runOn(orchestrator); } private Plugin findPlugin(List<Plugin> plugins, String pluginKey) { diff --git a/it/it-tests/src/test/resources/administration/suite/ProjectAdministrationTest/project-administration/multimodule-project-delete-version.html b/it/it-tests/src/test/resources/administration/suite/ProjectAdministrationTest/project-administration/multimodule-project-delete-version.html index 2c1a2f0ed60..58b94913711 100644 --- a/it/it-tests/src/test/resources/administration/suite/ProjectAdministrationTest/project-administration/multimodule-project-delete-version.html +++ b/it/it-tests/src/test/resources/administration/suite/ProjectAdministrationTest/project-administration/multimodule-project-delete-version.html @@ -23,7 +23,7 @@ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head profile="http://selenium-ide.openqa.org/profiles/test-case"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> - <title>project-modify-versions</title> + <title>multimodule-project-delete-version</title> </head> <body> <table cellpadding="1" cellspacing="1" border="1"> diff --git a/it/it-tests/src/test/resources/administration/suite/ProjectAdministrationTest/project-administration/multimodule-project-modify-version.html b/it/it-tests/src/test/resources/administration/suite/ProjectAdministrationTest/project-administration/multimodule-project-modify-version.html index aa3fb40c3c8..ef798b5cf36 100644 --- a/it/it-tests/src/test/resources/administration/suite/ProjectAdministrationTest/project-administration/multimodule-project-modify-version.html +++ b/it/it-tests/src/test/resources/administration/suite/ProjectAdministrationTest/project-administration/multimodule-project-modify-version.html @@ -23,7 +23,7 @@ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head profile="http://selenium-ide.openqa.org/profiles/test-case"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> - <title>project-modify-versions</title> + <title>multimodule-project-modify-version</title> </head> <body> <table cellpadding="1" cellspacing="1" border="1"> @@ -79,11 +79,6 @@ <td>RELEASE</td> </tr> <tr> - <td>keyUp</td> - <td>version_name_1</td> - <td>a</td> - </tr> - <tr> <td>clickAndWait</td> <td>save_version_1</td> <td></td> diff --git a/it/it-tests/src/test/resources/qualitygate/notifications/email_configuration.html b/it/it-tests/src/test/resources/qualitygate/notifications/email_configuration.html index 3d32118ce93..67b10d78c2f 100644 --- a/it/it-tests/src/test/resources/qualitygate/notifications/email_configuration.html +++ b/it/it-tests/src/test/resources/qualitygate/notifications/email_configuration.html @@ -39,7 +39,7 @@ <td></td> </tr> <tr> - <td>verifyValue</td> + <td>assertValue</td> <td>smtp_host</td> <td>localhost</td> </tr> |