aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2017-11-09 16:58:27 +0100
committerEric Hartmann <hartmann.eric@gmail.Com>2017-11-14 13:10:17 +0100
commita7b805384a46f7a700d3917757899e251f2f8207 (patch)
treefa66217a3ac072ea894378a7c555c73f70afb7ab /server
parentfca6f8677bd699540b6c9e5df98427b8f932e18b (diff)
downloadsonarqube-a7b805384a46f7a700d3917757899e251f2f8207.tar.gz
sonarqube-a7b805384a46f7a700d3917757899e251f2f8207.zip
Move pageobjects to new module sonar-qa-util
Diffstat (limited to 'server')
-rw-r--r--server/pom.xml1
-rw-r--r--server/sonar-qa-util/pom.xml46
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/SelenideConfig.java70
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/package-info.java23
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/BackgroundTaskItem.java65
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/BackgroundTasksPage.java45
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/EncryptionPage.java51
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java64
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/MarketplacePage.java60
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java265
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/NotificationsPage.java118
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectActivityPage.java60
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectAnalysisItem.java102
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectCodePage.java61
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectDashboardPage.java107
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectKeyPage.java100
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectLinkItem.java52
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectLinksPage.java44
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectPermissionsPage.java59
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectQualityGatePage.java44
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectsManagementPage.java58
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityGatePage.java54
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityProfilePage.java54
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RuleDetails.java39
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RuleItem.java41
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RulesPage.java66
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/SystemInfoPage.java46
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/SystemInfoPageItem.java85
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/issues/Issue.java64
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/issues/IssuesPage.java82
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/measures/MeasureContent.java61
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/measures/MeasuresPage.java97
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/organization/MemberItem.java94
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/organization/MembersPage.java81
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/package-info.java23
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/FacetItem.java49
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/ProjectItem.java37
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/ProjectsPage.java116
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/settings/PropertySetInput.java47
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/settings/SettingsPage.java80
40 files changed, 2711 insertions, 0 deletions
diff --git a/server/pom.xml b/server/pom.xml
index 99a700f2a58..5b27942fb00 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -23,6 +23,7 @@
<module>sonar-ce</module>
<module>sonar-plugin-bridge</module>
<module>sonar-web</module>
+ <module>sonar-qa-util</module>
</modules>
<profiles>
diff --git a/server/sonar-qa-util/pom.xml b/server/sonar-qa-util/pom.xml
new file mode 100644
index 00000000000..a9534332a89
--- /dev/null
+++ b/server/sonar-qa-util/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.sonarsource.sonarqube</groupId>
+ <artifactId>server</artifactId>
+ <version>7.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>sonar-qa-util</artifactId>
+ <name>SonarQube :: Utilities for QA Tests</name>
+
+ <properties>
+ <sonar.coverage.exclusions>src/main/java/**/*</sonar.coverage.exclusions>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.codeborne</groupId>
+ <artifactId>selenide</artifactId>
+ <version>4.4.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.sonarsource.orchestrator</groupId>
+ <artifactId>sonar-orchestrator</artifactId>
+ <version>${orchestrator.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <!-- required for selenide -->
+ <version>21.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/SelenideConfig.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/SelenideConfig.java
new file mode 100644
index 00000000000..155ded5ee56
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/SelenideConfig.java
@@ -0,0 +1,70 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util;
+
+import com.codeborne.selenide.Configuration;
+import com.codeborne.selenide.WebDriverRunner;
+import com.sonar.orchestrator.Orchestrator;
+import java.util.stream.Collectors;
+import org.openqa.selenium.WebDriver;
+
+import static java.util.Arrays.stream;
+
+public class SelenideConfig {
+
+ private enum Browser {
+ firefox("(v46 and lower)"),
+ marionette("(recent Firefox, require Geckodriver)"),
+ chrome("(require Chromedriver)");
+
+ private final String label;
+
+ Browser(String label) {
+ this.label = label;
+ }
+
+ static Browser of(String s) {
+ try {
+ return Browser.valueOf(s);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Invalid browser: " + s + ". Supported values are " +
+ stream(values()).map(b -> b.name() + " " + b.label).collect(Collectors.joining(", ")));
+ }
+ }
+ }
+
+ public static WebDriver configure(Orchestrator orchestrator) {
+ String browserKey = orchestrator.getConfiguration().getString("orchestrator.browser", Browser.firefox.name());
+ Browser browser = Browser.of(browserKey);
+ Configuration.browser = browser.name();
+ Configuration.baseUrl = orchestrator.getServer().getUrl();
+ Configuration.timeout = 8_000;
+ Configuration.reportsFolder = "target/screenshots";
+ Configuration.screenshots = true;
+ Configuration.captureJavascriptErrors = true;
+ Configuration.savePageSource = true;
+ Configuration.browserSize = "1280x1024";
+ return getWebDriver();
+ }
+
+ static WebDriver getWebDriver() {
+ return WebDriverRunner.getWebDriver();
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/package-info.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/package-info.java
new file mode 100644
index 00000000000..696f5531c1d
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonarqube.qa.util;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/BackgroundTaskItem.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/BackgroundTaskItem.java
new file mode 100644
index 00000000000..0c86d3293b1
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/BackgroundTaskItem.java
@@ -0,0 +1,65 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+
+public class BackgroundTaskItem {
+
+ private final SelenideElement elt;
+
+ public BackgroundTaskItem(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public SelenideElement getComponent() {
+ return elt.$("td:nth-child(2)");
+ }
+
+ public BackgroundTaskItem openActions() {
+ elt.$(".js-task-action > .dropdown-toggle").click();
+ elt.$(".js-task-action > .dropdown-menu").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public BackgroundTaskItem openScannerContext() {
+ elt.$(".js-task-show-scanner-context").click();
+ Selenide.$(".js-task-scanner-context").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public BackgroundTaskItem assertScannerContextContains(String text) {
+ Selenide.$(".js-task-scanner-context").should(Condition.hasText(text));
+ return this;
+ }
+
+ public BackgroundTaskItem openErrorStacktrace() {
+ elt.$(".js-task-show-stacktrace").click();
+ Selenide.$(".js-task-stacktrace").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public BackgroundTaskItem assertErrorStacktraceContains(String text) {
+ Selenide.$(".js-task-stacktrace").should(Condition.hasText(text));
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/BackgroundTasksPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/BackgroundTasksPage.java
new file mode 100644
index 00000000000..a14bc2cebff
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/BackgroundTasksPage.java
@@ -0,0 +1,45 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.Selenide;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.openqa.selenium.By;
+
+public class BackgroundTasksPage {
+
+ public BackgroundTasksPage() {
+ Selenide.$(By.cssSelector(".background-tasks")).should(Condition.exist);
+ }
+
+ public ElementsCollection getTasks() {
+ return Selenide.$$(".background-tasks > tbody > tr");
+ }
+
+ public List<BackgroundTaskItem> getTasksAsItems() {
+ return getTasks()
+ .stream()
+ .map(BackgroundTaskItem::new)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/EncryptionPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/EncryptionPage.java
new file mode 100644
index 00000000000..0e3bac79722
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/EncryptionPage.java
@@ -0,0 +1,51 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+
+public class EncryptionPage extends Navigation {
+
+ public EncryptionPage() {
+ Selenide.$("#encryption-page").should(Condition.exist);
+ }
+
+ public SelenideElement generationForm() {
+ return Selenide.$("#generate-secret-key-form");
+ }
+
+ public SelenideElement newSecretKey() {
+ return Selenide.$("#secret-key");
+ }
+
+ public String encryptValue(String value) {
+ Selenide.$("#encryption-form-value").val(value);
+ Selenide.$("#encryption-form").submit();
+ return Selenide.$("#encrypted-value").shouldBe(Condition.visible).val();
+ }
+
+ public EncryptionPage generateNewKey() {
+ Selenide.$("#encryption-new-key-form").submit();
+ Selenide.$("#generate-secret-key-form").shouldBe(Condition.visible);
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java
new file mode 100644
index 00000000000..b210e01fb2e
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+import org.openqa.selenium.By;
+
+public class LoginPage {
+
+ public LoginPage() {
+ Selenide.$("#login_form").should(Condition.exist);
+ }
+
+ public Navigation submitCredentials(String login) {
+ return submitCredentials(login, login, Navigation.class);
+ }
+
+ public Navigation submitCredentials(String login, String password) {
+ return submitCredentials(login, password, Navigation.class);
+ }
+
+ public Navigation useOAuth2() {
+ Selenide.$(".oauth-providers a").click();
+ return Selenide.page(Navigation.class);
+ }
+
+ public LoginPage submitWrongCredentials(String login, String password) {
+ Selenide.$("#login").val(login);
+ Selenide.$("#password").val(password);
+ Selenide.$(By.name("commit")).click();
+ return Selenide.page(LoginPage.class);
+ }
+
+ public SelenideElement getErrorMessage() {
+ return Selenide.$(".process-spinner-failed");
+ }
+
+ private <T> T submitCredentials(String login, String password, Class<T> expectedResultPage) {
+ Selenide.$("#login").val(login);
+ Selenide.$("#password").val(password);
+ Selenide.$(By.name("commit")).click();
+ Selenide.$("#login").should(Condition.disappear);
+ return Selenide.page(expectedResultPage);
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/MarketplacePage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/MarketplacePage.java
new file mode 100644
index 00000000000..908bad3b3e9
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/MarketplacePage.java
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+
+public class MarketplacePage {
+
+ public MarketplacePage() {
+ Selenide.$("#marketplace-page").should(Condition.exist);
+ }
+
+ public MarketplacePage hasPendingPlugins(String text) {
+ Selenide.$(".js-pending").should(Condition.exist).shouldHave(Condition.text(text));
+ return this;
+ }
+
+ public MarketplacePage hasPluginsCount(int count) {
+ Selenide.$$("#marketplace-plugins>ul>li").shouldHaveSize(count);
+ return this;
+ }
+
+ public MarketplacePage hasPluginWithText(String name, String text) {
+ getPlugin(name).shouldHave(Condition.text(text));
+ return this;
+ }
+
+ public MarketplacePage searchPlugin(String search) {
+ Selenide.$("#marketplace-search input.search-box-input").should(Condition.exist).sendKeys(search);
+ return this;
+ }
+
+ public MarketplacePage uninstallPlugin(String name) {
+ getPlugin(name).$("button.js-uninstall").click();
+ return this;
+ }
+
+ private SelenideElement getPlugin(String name) {
+ return Selenide.$$(".js-plugin-name").findBy(Condition.text(name)).should(Condition.exist).parent().parent().parent();
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java
new file mode 100644
index 00000000000..67cea197772
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java
@@ -0,0 +1,265 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+import com.codeborne.selenide.WebDriverRunner;
+import com.sonar.orchestrator.Orchestrator;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.function.Consumer;
+import javax.annotation.Nullable;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.html5.WebStorage;
+import org.sonarqube.qa.util.SelenideConfig;
+import org.sonarqube.qa.util.pageobjects.issues.IssuesPage;
+import org.sonarqube.qa.util.pageobjects.measures.MeasuresPage;
+import org.sonarqube.qa.util.pageobjects.organization.MembersPage;
+import org.sonarqube.qa.util.pageobjects.projects.ProjectsPage;
+import org.sonarqube.qa.util.pageobjects.settings.SettingsPage;
+
+public class Navigation {
+
+ public Navigation() {
+ Selenide.$("#content").shouldBe(Condition.exist);
+ }
+
+ public static Navigation create(Orchestrator orchestrator) {
+ WebDriver driver = SelenideConfig.configure(orchestrator);
+ driver.manage().deleteAllCookies();
+ clearStorage(d -> d.getLocalStorage().clear());
+ clearStorage(d -> d.getSessionStorage().clear());
+ clearStorage(d -> Selenide.clearBrowserLocalStorage());
+ return Selenide.open("/", Navigation.class);
+ }
+
+ private static void clearStorage(Consumer<WebStorage> cleaner) {
+ try {
+ cleaner.accept((WebStorage) WebDriverRunner.getWebDriver());
+ } catch (Exception e) {
+ // ignore, it may occur when the first test opens browser. No pages are loaded
+ // and local/session storages are not available yet.
+ // Example with Chrome: "Failed to read the 'localStorage' property from 'Window': Storage is disabled inside 'data:' URLs."
+ }
+ }
+
+ public Navigation openHome() {
+ return open("/", Navigation.class);
+ }
+
+ public ProjectsPage openProjects() {
+ return open("/projects", ProjectsPage.class);
+ }
+
+ public ProjectsPage openProjects(String organization) {
+ return open("/organizations/" + organization + "/projects", ProjectsPage.class);
+ }
+
+ public ProjectsPage openProjectsWithQuery(String query) {
+ return open("/projects?" + query, ProjectsPage.class);
+ }
+
+ public IssuesPage openIssues() {
+ return open("/issues", IssuesPage.class);
+ }
+
+ public IssuesPage openIssues(String organization) {
+ return open("/organizations/" + organization + "/issues", IssuesPage.class);
+ }
+
+ public IssuesPage openComponentIssues(String component) {
+ return open("/component_issues?id=" + component, IssuesPage.class);
+ }
+
+ public ProjectDashboardPage openProjectDashboard(String projectKey) {
+ // TODO encode projectKey
+ String url = "/dashboard?id=" + projectKey;
+ return open(url, ProjectDashboardPage.class);
+ }
+
+ public ProjectLinksPage openProjectLinks(String projectKey) {
+ // TODO encode projectKey
+ String url = "/project/links?id=" + projectKey;
+ return open(url, ProjectLinksPage.class);
+ }
+
+ public QualityGatePage openQualityGates() {
+ String url = "/quality_gates";
+ return open(url, QualityGatePage.class);
+ }
+
+ public QualityGatePage openQualityGates(String organization) {
+ String url = "/organizations/" + organization + "/quality_gates";
+ return open(url, QualityGatePage.class);
+ }
+
+ public ProjectQualityGatePage openProjectQualityGate(String projectKey) {
+ // TODO encode projectKey
+ String url = "/project/quality_gate?id=" + projectKey;
+ return open(url, ProjectQualityGatePage.class);
+ }
+
+ public ProjectKeyPage openProjectKey(String projectKey) {
+ // TODO encode projectKey
+ String url = "/project/key?id=" + projectKey;
+ return open(url, ProjectKeyPage.class);
+ }
+
+ public ProjectActivityPage openProjectActivity(String projectKey) {
+ // TODO encode projectKey
+ String url = "/project/activity?id=" + projectKey;
+ return open(url, ProjectActivityPage.class);
+ }
+
+ public MeasuresPage openProjectMeasures(String projectKey) {
+ // TODO encode projectKey
+ String url = "/component_measures?id=" + projectKey;
+ return open(url, MeasuresPage.class);
+ }
+
+ public ProjectCodePage openCode(String projectKey) {
+ // TODO encode projectKey
+ String url = "/code?id=" + projectKey;
+ return open(url, ProjectCodePage.class);
+ }
+
+ public ProjectCodePage openCode(String projectKey, String selected) {
+ // TODO encode projectKey and selected
+ String url = "/code?id=" + projectKey + "&selected=" + selected;
+ return open(url, ProjectCodePage.class);
+ }
+
+ public MembersPage openOrganizationMembers(String orgKey) {
+ String url = "/organizations/" + orgKey + "/members";
+ return open(url, MembersPage.class);
+ }
+
+ public QualityProfilePage openQualityProfile(String language, String name, String organization) {
+ String profileUrl = "/quality_profiles/show?language=" + language + "&name=" + name;
+ return open("/organizations/" + organization + profileUrl, QualityProfilePage.class);
+ }
+
+ public BackgroundTasksPage openBackgroundTasksPage() {
+ return open("/background_tasks", BackgroundTasksPage.class);
+ }
+
+ public SettingsPage openSettings(@Nullable String projectKey) throws UnsupportedEncodingException {
+ String url = projectKey != null ? "/project/settings?id=" + URLEncoder.encode(projectKey, "UTF-8") : "/settings";
+ return open(url, SettingsPage.class);
+ }
+
+ public EncryptionPage openEncryption() {
+ return open("/settings/encryption", EncryptionPage.class);
+ }
+
+ public SystemInfoPage openSystemInfo() {
+ return open("/admin/system", SystemInfoPage.class);
+ }
+
+ public MarketplacePage openMarketplace() {
+ return open("/admin/marketplace", MarketplacePage.class);
+ }
+
+ public NotificationsPage openNotifications() {
+ return open("/account/notifications", NotificationsPage.class);
+ }
+
+ public ProjectPermissionsPage openProjectPermissions(String projectKey) {
+ String url = "/project_roles?id=" + projectKey;
+ return open(url, ProjectPermissionsPage.class);
+ }
+
+ public ProjectsManagementPage openProjectsManagement() {
+ return open("/projects_admin", ProjectsManagementPage.class);
+ }
+
+ public LoginPage openLogin() {
+ return open("/sessions/login", LoginPage.class);
+ }
+
+ public void open(String relativeUrl) {
+ Selenide.open(relativeUrl);
+ }
+
+ public <P> P open(String relativeUrl, Class<P> pageObjectClassClass) {
+ return Selenide.open(relativeUrl, pageObjectClassClass);
+ }
+
+ public Navigation shouldBeLoggedIn() {
+ loggedInDropdown().should(Condition.visible);
+ return this;
+ }
+
+ public Navigation shouldNotBeLoggedIn() {
+ logInLink().should(Condition.visible);
+ return this;
+ }
+
+ public LoginPage logIn() {
+ logInLink().click();
+ return Selenide.page(LoginPage.class);
+ }
+
+ public Navigation logOut() {
+ SelenideElement dropdown = loggedInDropdown();
+ // click must be on the <a> but not on the dropdown <li>
+ // for compatibility with phantomjs
+ dropdown.find(".dropdown-toggle").click();
+ dropdown.find(By.linkText("Log out")).click();
+ return this;
+ }
+
+ public RulesPage openRules() {
+ return open("/coding_rules", RulesPage.class);
+ }
+
+ public SelenideElement clickOnQualityProfiles() {
+ return Selenide.$(By.linkText("Quality Profiles"));
+ }
+
+ public SelenideElement getRightBar() {
+ return Selenide.$("#global-navigation .navbar-right");
+ }
+
+ public SelenideElement getFooter() {
+ return Selenide.$("#footer");
+ }
+
+ public SelenideElement getErrorMessage() {
+ return Selenide.$("#error");
+ }
+
+ private SelenideElement logInLink() {
+ return Selenide.$(By.linkText("Log in"));
+ }
+
+ private SelenideElement loggedInDropdown() {
+ return Selenide.$(".js-user-authenticated");
+ }
+
+ public Navigation shouldBeRedirectedToLogin() {
+ Selenide.$("#login_form").should(Condition.visible);
+ return this;
+ }
+
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/NotificationsPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/NotificationsPage.java
new file mode 100644
index 00000000000..bd4911a94c6
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/NotificationsPage.java
@@ -0,0 +1,118 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+
+public class NotificationsPage extends Navigation {
+
+ private final String EMAIL = "EmailNotificationChannel";
+
+ public NotificationsPage() {
+ Selenide.$("#account-page").shouldHave(Condition.text("Overall notifications"));
+ }
+
+ public NotificationsPage shouldHaveGlobalNotification(String type) {
+ return shouldHaveGlobalNotification(type, EMAIL);
+ }
+
+ public NotificationsPage shouldHaveGlobalNotification(String type, String channel) {
+ return shouldBeChecked(globalCheckboxSelector(type, channel));
+ }
+
+ public NotificationsPage shouldNotHaveGlobalNotification(String type) {
+ return shouldNotHaveGlobalNotification(type, EMAIL);
+ }
+
+ public NotificationsPage shouldNotHaveGlobalNotification(String type, String channel) {
+ return shouldNotBeChecked(globalCheckboxSelector(type, channel));
+ }
+
+ public NotificationsPage shouldHaveProjectNotification(String project, String type, String channel) {
+ return shouldBeChecked(projectCheckboxSelector(project, type, channel));
+ }
+
+ public NotificationsPage shouldNotHaveProjectNotification(String project, String type, String channel) {
+ return shouldNotBeChecked(projectCheckboxSelector(project, type, channel));
+ }
+
+ public NotificationsPage addGlobalNotification(String type) {
+ return addGlobalNotification(type, EMAIL);
+ }
+
+ public NotificationsPage addGlobalNotification(String type, String channel) {
+ shouldNotHaveGlobalNotification(type, channel);
+ toggleCheckbox(globalCheckboxSelector(type, channel));
+ shouldHaveGlobalNotification(type, channel);
+ return this;
+ }
+
+ public NotificationsPage removeGlobalNotification(String type) {
+ return removeGlobalNotification(type, EMAIL);
+ }
+
+ public NotificationsPage removeGlobalNotification(String type, String channel) {
+ shouldHaveGlobalNotification(type, channel);
+ toggleCheckbox(globalCheckboxSelector(type, channel));
+ shouldNotHaveGlobalNotification(type, channel);
+ return this;
+ }
+
+ public NotificationsPage addProjectNotification(String project, String type, String channel) {
+ shouldNotHaveProjectNotification(project, type, channel);
+ toggleCheckbox(projectCheckboxSelector(project, type, channel));
+ shouldHaveProjectNotification(project, type, channel);
+ return this;
+ }
+
+ public NotificationsPage removeProjectNotification(String project, String type, String channel) {
+ shouldHaveProjectNotification(project, type, channel);
+ toggleCheckbox(projectCheckboxSelector(project, type, channel));
+ shouldNotHaveProjectNotification(project, type, channel);
+ return this;
+ }
+
+ private String globalCheckboxSelector(String type, String channel) {
+ return "#global-notification-" + type + "-" + channel;
+ }
+
+ private String projectCheckboxSelector(String project, String type, String channel) {
+ return "#project-notification-" + project + "-" + type + "-" + channel;
+ }
+
+ private NotificationsPage shouldBeChecked(String selector) {
+ Selenide.$(selector)
+ .shouldBe(Condition.visible)
+ .shouldHave(Condition.cssClass("icon-checkbox-checked"));
+ return this;
+ }
+
+ private NotificationsPage shouldNotBeChecked(String selector) {
+ Selenide.$(selector)
+ .shouldBe(Condition.visible)
+ .shouldNotHave(Condition.cssClass("icon-checkbox-checked"));
+ return this;
+ }
+
+ private void toggleCheckbox(String selector) {
+ Selenide.$(selector).click();
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectActivityPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectActivityPage.java
new file mode 100644
index 00000000000..ad8206cd47d
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectActivityPage.java
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.Selenide;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ProjectActivityPage {
+
+ public ProjectActivityPage() {
+ Selenide.$("#project-activity").should(Condition.exist);
+ }
+
+ public ElementsCollection getAnalyses() {
+ return Selenide.$$(".project-activity-analysis");
+ }
+
+ public List<ProjectAnalysisItem> getAnalysesAsItems() {
+ return getAnalyses()
+ .stream()
+ .map(ProjectAnalysisItem::new)
+ .collect(Collectors.toList());
+ }
+
+ public ProjectAnalysisItem getLastAnalysis() {
+ return new ProjectAnalysisItem(Selenide.$(".project-activity-analysis"));
+ }
+
+ public ProjectAnalysisItem getFirstAnalysis() {
+ return new ProjectAnalysisItem(Selenide.$$(".project-activity-analysis").last());
+ }
+
+ public ProjectActivityPage assertFirstAnalysisOfTheDayHasText(String day, String text) {
+ Selenide.$("#project-activity")
+ .find(".project-activity-day[data-day=\"" + day + "\"]")
+ .find(".project-activity-analysis")
+ .should(Condition.hasText(text));
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectAnalysisItem.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectAnalysisItem.java
new file mode 100644
index 00000000000..2f6d4449c4d
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectAnalysisItem.java
@@ -0,0 +1,102 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+
+public class ProjectAnalysisItem {
+
+ private final SelenideElement elt;
+
+ public ProjectAnalysisItem(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public ProjectAnalysisItem shouldHaveEventWithText(String text) {
+ elt.find(".project-activity-events").shouldHave(Condition.text(text));
+ return this;
+ }
+
+ public ProjectAnalysisItem shouldHaveDeleteButton() {
+ elt.find(".js-analysis-actions").click();
+ elt.find(".js-delete-analysis").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public ProjectAnalysisItem shouldNotHaveDeleteButton() {
+ elt.find(".js-analysis-actions").click();
+ elt.find(".js-delete-analysis").shouldNotBe(Condition.visible);
+ return this;
+ }
+
+ public void delete() {
+ elt.find(".js-analysis-actions").click();
+ elt.find(".js-delete-analysis").click();
+
+ SelenideElement modal = Selenide.$(".modal");
+ modal.shouldBe(Condition.visible);
+ modal.find("button[type=\"submit\"]").click();
+
+ elt.shouldNotBe(Condition.visible);
+ }
+
+ public ProjectAnalysisItem addCustomEvent(String name) {
+ elt.find(".js-analysis-actions").click();
+ elt.find(".js-add-event").click();
+
+ SelenideElement modal = Selenide.$(".modal");
+ modal.shouldBe(Condition.visible);
+ modal.find("input").setValue(name);
+ modal.find("button[type=\"submit\"]").click();
+
+ elt.find(".project-activity-event:first-child").shouldHave(Condition.text(name));
+ return this;
+ }
+
+ public ProjectAnalysisItem changeFirstEvent(String newName) {
+ SelenideElement firstEvent = elt.find(".project-activity-event:first-child");
+ firstEvent.find(".js-change-event").click();
+
+ SelenideElement modal = Selenide.$(".modal");
+ modal.shouldBe(Condition.visible);
+ modal.find("input").setValue(newName);
+ modal.find("button[type=\"submit\"]").click();
+
+ firstEvent.shouldHave(Condition.text(newName));
+ return this;
+ }
+
+ public ProjectAnalysisItem deleteFirstEvent() {
+ int eventsCount = elt.findAll(".project-activity-event").size();
+
+ SelenideElement firstEvent = elt.find(".project-activity-event:first-child");
+ firstEvent.find(".js-delete-event").click();
+
+ SelenideElement modal = Selenide.$(".modal");
+ modal.shouldBe(Condition.visible);
+ modal.find("button[type=\"submit\"]").click();
+
+ elt.findAll(".project-activity-event").shouldHaveSize(eventsCount - 1);
+
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectCodePage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectCodePage.java
new file mode 100644
index 00000000000..42bb86748a2
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectCodePage.java
@@ -0,0 +1,61 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+
+public class ProjectCodePage {
+
+ public ProjectCodePage() {
+ }
+
+ public ProjectCodePage openFirstComponent() {
+ Selenide.$$(".code-name-cell a").first().click();
+ return this;
+ }
+
+ public ProjectCodePage search(String query) {
+ Selenide.$(".code-search .search-box-input").val(query);
+ return this;
+ }
+
+ public ProjectCodePage shouldHaveComponent(String name) {
+ Selenide.$(".code-components").shouldHave(Condition.text(name));
+ return this;
+ }
+
+ public ProjectCodePage shouldHaveCode(String code) {
+ Selenide.$(".code-components .source-viewer").shouldHave(Condition.text(code));
+ return this;
+ }
+
+ public ProjectCodePage shouldHaveBreadcrumbs(String... breadcrumbs) {
+ for (String breadcrumb : breadcrumbs) {
+ Selenide.$(".code-breadcrumbs").shouldHave(Condition.text(breadcrumb));
+ }
+ return this;
+ }
+
+ public ProjectCodePage shouldSearchResult(String name) {
+ Selenide.$(".code-search-with-results").shouldHave(Condition.text(name));
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectDashboardPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectDashboardPage.java
new file mode 100644
index 00000000000..4db286489dd
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectDashboardPage.java
@@ -0,0 +1,107 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+import java.util.Arrays;
+import org.openqa.selenium.By;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+
+public class ProjectDashboardPage {
+
+ public ProjectDashboardPage() {
+ Selenide.$(".overview").shouldBe(Condition.visible);
+ }
+
+ public SelenideElement getLinesOfCode() {
+ SelenideElement element = Selenide.$("#overview-ncloc");
+ element.shouldBe(Condition.visible);
+ return element;
+ }
+
+ public SelenideElement getLanguageDistribution() {
+ SelenideElement element = Selenide.$("#overview-language-distribution");
+ element.shouldBe(Condition.visible);
+ return element;
+ }
+
+ public SelenideElement getOverviewMeasure(String measure) {
+ ElementsCollection measures = Selenide.$$(".overview-domain-measure");
+ SelenideElement element = measures.find(Condition.text(measure)).shouldBe(Condition.visible);
+ return element;
+ }
+
+ private SelenideElement getTagsMeta() {
+ SelenideElement element = Selenide.$(".overview-meta-tags");
+ element.shouldBe(Condition.visible);
+ return element;
+ }
+
+ public ProjectDashboardPage shouldHaveTags(String... tags) {
+ String tagsList = String.join(", ", Arrays.asList(tags));
+ this.getTagsMeta().$(".tags-list > span").should(Condition.hasText(tagsList));
+ return this;
+ }
+
+ public ProjectDashboardPage shouldNotBeEditable() {
+ SelenideElement tagsElem = this.getTagsMeta();
+ tagsElem.$("button").shouldNot(Condition.exist);
+ tagsElem.$("div.multi-select").shouldNot(Condition.exist);
+ return this;
+ }
+
+ public ProjectDashboardPage shouldBeEditable() {
+ SelenideElement tagsElem = this.getTagsMeta();
+ tagsElem.$("button").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public ProjectDashboardPage openTagEditor() {
+ SelenideElement tagsElem = this.getTagsMeta();
+ tagsElem.$("button").shouldBe(Condition.visible).click();
+ tagsElem.$("div.multi-select").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public SelenideElement getTagAtIdx(Integer idx) {
+ SelenideElement tagsElem = this.getTagsMeta();
+ tagsElem.$("div.multi-select").shouldBe(Condition.visible);
+ return tagsElem.$$("ul.menu a").get(idx);
+ }
+
+ public ProjectDashboardPage sendKeysToTagsInput(CharSequence... charSequences) {
+ SelenideElement tagsInput = this.getTagsMeta().find("input");
+ tagsInput.sendKeys(charSequences);
+ return this;
+ }
+
+ public ProjectDashboardPage hasQualityGateLink(String name, String link) {
+ SelenideElement elem = Selenide.$$(".overview-meta-card")
+ .findBy(Condition.text("Quality Gate")).should(Condition.exist)
+ .find(By.linkText(name)).should(Condition.exist);
+ assertThat(elem.attr("href")).endsWith(link);
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectKeyPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectKeyPage.java
new file mode 100644
index 00000000000..5a3e5ec678b
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectKeyPage.java
@@ -0,0 +1,100 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+
+public class ProjectKeyPage {
+
+ public ProjectKeyPage() {
+ Selenide.$("#project-key").should(Condition.exist);
+ }
+
+ public ProjectKeyPage assertSimpleUpdate() {
+ Selenide.$("#update-key-new-key").shouldBe(Condition.visible);
+ Selenide.$("#update-key-submit").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public ProjectKeyPage trySimpleUpdate(String newKey) {
+ Selenide.$("#update-key-new-key").val(newKey);
+ Selenide.$("#update-key-submit").click();
+ Selenide.$("#update-key-confirm").click();
+ return this;
+ }
+
+ public ProjectKeyPage openFineGrainedUpdate() {
+ Selenide.$("#update-key-tab-fine").click();
+ Selenide.$("#project-key-fine-grained-update").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public ProjectKeyPage tryFineGrainedUpdate(String key, String newKey) {
+ SelenideElement form = Selenide.$(".js-fine-grained-update[data-key=\"" + key + "\"]");
+ form.shouldBe(Condition.visible);
+
+ form.$("input").val(newKey);
+ form.$("button").click();
+
+ Selenide.$("#update-key-confirm").click();
+ return this;
+ }
+
+ public ProjectKeyPage assertBulkChange() {
+ Selenide.$("#bulk-update-replace").shouldBe(Condition.visible);
+ Selenide.$("#bulk-update-by").shouldBe(Condition.visible);
+ Selenide.$("#bulk-update-see-results").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public ProjectKeyPage simulateBulkChange(String replace, String by) {
+ Selenide.$("#bulk-update-replace").val(replace);
+ Selenide.$("#bulk-update-by").val(by);
+ Selenide.$("#bulk-update-see-results").click();
+
+ Selenide.$("#bulk-update-simulation").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public ProjectKeyPage assertBulkChangeSimulationResult(String oldKey, String newKey) {
+ SelenideElement row = Selenide.$("#bulk-update-results").$("[data-key=\"" + oldKey + "\"]");
+ row.$(".js-old-key").should(Condition.hasText(oldKey));
+ row.$(".js-new-key").should(Condition.hasText(newKey));
+ return this;
+ }
+
+ public ProjectKeyPage assertDuplicated(String oldKey) {
+ SelenideElement row = Selenide.$("#bulk-update-results").$("[data-key=\"" + oldKey + "\"]");
+ row.$(".js-new-key").$(".badge-danger").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public ProjectKeyPage confirmBulkUpdate() {
+ Selenide.$("#bulk-update-confirm").click();
+ return this;
+ }
+
+ public ProjectKeyPage assertSuccessfulBulkUpdate() {
+ Selenide.$("#project-key-bulk-update").$(".alert.alert-success").shouldBe(Condition.visible);
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectLinkItem.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectLinkItem.java
new file mode 100644
index 00000000000..7444ca554ac
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectLinkItem.java
@@ -0,0 +1,52 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.SelenideElement;
+import org.openqa.selenium.NoSuchElementException;
+
+public class ProjectLinkItem {
+
+ private final SelenideElement elt;
+
+ public ProjectLinkItem(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public SelenideElement getName() {
+ return elt.$(".js-name");
+ }
+
+ public SelenideElement getType() {
+ try {
+ return elt.$(".js-type");
+ } catch (NoSuchElementException e) {
+ return null;
+ }
+ }
+
+ public SelenideElement getUrl() {
+ return elt.$(".js-url");
+ }
+
+ public SelenideElement getDeleteButton() {
+ return elt.$(".js-delete-button");
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectLinksPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectLinksPage.java
new file mode 100644
index 00000000000..8f9e8860f5a
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectLinksPage.java
@@ -0,0 +1,44 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.Selenide;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ProjectLinksPage {
+
+ public ProjectLinksPage() {
+ Selenide.$("#project-links").should(Condition.exist);
+ }
+
+ public ElementsCollection getLinks() {
+ return Selenide.$$("#project-links tr[data-name]");
+ }
+
+ public List<ProjectLinkItem> getLinksAsItems() {
+ return getLinks()
+ .stream()
+ .map(ProjectLinkItem::new)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectPermissionsPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectPermissionsPage.java
new file mode 100644
index 00000000000..0fabc151b7d
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectPermissionsPage.java
@@ -0,0 +1,59 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+
+public class ProjectPermissionsPage {
+
+ public ProjectPermissionsPage() {
+ Selenide.$("#project-permissions-page").should(Condition.exist);
+ }
+
+ public ProjectPermissionsPage shouldBePublic() {
+ Selenide.$("#visibility-public .icon-radio.is-checked").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public ProjectPermissionsPage shouldBePrivate() {
+ Selenide.$("#visibility-private .icon-radio.is-checked").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public ProjectPermissionsPage turnToPublic() {
+ Selenide.$("#visibility-public").click();
+ Selenide.$("#confirm-turn-to-public").click();
+ shouldBePublic();
+ return this;
+ }
+
+ public ProjectPermissionsPage turnToPrivate() {
+ Selenide.$("#visibility-private").click();
+ shouldBePrivate();
+ return this;
+ }
+
+ public ProjectPermissionsPage shouldNotAllowPrivate() {
+ Selenide.$("#visibility-private").shouldHave(Condition.cssClass("text-muted"));
+ Selenide.$(".upgrade-organization-box").shouldBe(Condition.visible);
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectQualityGatePage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectQualityGatePage.java
new file mode 100644
index 00000000000..0cf3904c640
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectQualityGatePage.java
@@ -0,0 +1,44 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+
+public class ProjectQualityGatePage {
+
+ public ProjectQualityGatePage() {
+ Selenide.$("#project-quality-gate").should(Condition.exist);
+ }
+
+ public SelenideElement getSelectedQualityGate() {
+ return Selenide.$(".Select-value-label");
+ }
+
+ public void assertNotSelected() {
+ Selenide.$(".Select-placeholder").should(Condition.exist);
+ Selenide.$(".Select-value-label").shouldNot(Condition.exist);
+ }
+
+ public void setQualityGate(String name) {
+ Selenide.$(".Select-input input").val(name).pressEnter();
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectsManagementPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectsManagementPage.java
new file mode 100644
index 00000000000..529c98abb25
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/ProjectsManagementPage.java
@@ -0,0 +1,58 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+
+public class ProjectsManagementPage {
+
+ public ProjectsManagementPage() {
+ Selenide.$("#projects-management-page").should(Condition.exist);
+ }
+
+ public ProjectsManagementPage shouldHaveProjectsCount(int count) {
+ Selenide.$$("#projects-management-page-projects tbody tr").shouldHaveSize(count);
+ return this;
+ }
+
+ public ProjectsManagementPage shouldHaveProject(String key) {
+ Selenide.$("#projects-management-page-projects").shouldHave(Condition.text(key));
+ return this;
+ }
+
+ public ProjectsManagementPage createProject(String key, String name, String visibility) {
+ Selenide.$("#create-project").click();
+ Selenide.$("#create-project-name").val(key);
+ Selenide.$("#create-project-key").val(name);
+ Selenide.$("#visibility-" + visibility).click();
+ Selenide.$("#create-project-submit").submit();
+ return this;
+ }
+
+ public ProjectsManagementPage bulkApplyPermissionTemplate(String template) {
+ Selenide.$(".js-bulk-apply-permission-template").click();
+ Selenide.$(".modal .Select-value").click();
+ Selenide.$$(".modal .Select-option").findBy(Condition.text(template)).click();
+ Selenide.$(".modal-foot button").click();
+ Selenide.$(".modal-body .alert-success").shouldBe(Condition.visible);
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityGatePage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityGatePage.java
new file mode 100644
index 00000000000..2f8f1669123
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityGatePage.java
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+
+public class QualityGatePage {
+ public QualityGatePage() {
+ Selenide.$("#quality-gates-page").shouldBe(Condition.visible);
+ }
+
+ public QualityGatePage countQualityGates(Integer count) {
+ Selenide.$$("#quality-gates-page .list-group-item").shouldHaveSize(count);
+ return this;
+ }
+
+ public QualityGatePage canCreateQG() {
+ Selenide.$("#quality-gate-add").should(Condition.exist).shouldBe(Condition.visible);
+ return this;
+ }
+
+ public QualityGatePage canNotCreateQG() {
+ Selenide.$("#quality-gate-add").shouldNot(Condition.exist);
+ return this;
+ }
+
+ public QualityGatePage displayIntro() {
+ Selenide.$(".search-navigator-intro").should(Condition.exist).shouldBe(Condition.visible);
+ return this;
+ }
+
+ public QualityGatePage displayQualityGateDetail(String qualityGateName) {
+ Selenide.$(".layout-page-main-header").shouldHave(Condition.text(qualityGateName));
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityProfilePage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityProfilePage.java
new file mode 100644
index 00000000000..88b009687b0
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityProfilePage.java
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+
+public class QualityProfilePage {
+ public QualityProfilePage() {
+ Selenide.$("#quality-profile").shouldBe(Condition.visible);
+ }
+
+ public QualityProfilePage shouldHaveMissingSonarWayRules(Integer nbRules) {
+ Selenide.$(".quality-profile-rules-sonarway-missing")
+ .shouldBe(Condition.visible)
+ .$("a").shouldHave(Condition.text(nbRules.toString()));
+ return this;
+ }
+
+ public RulesPage showMissingSonarWayRules() {
+ Selenide.$(".quality-profile-rules-sonarway-missing")
+ .shouldBe(Condition.visible).$("a").click();
+ Selenide.$(".coding-rules").shouldBe(Condition.visible);
+ return Selenide.page(RulesPage.class);
+ }
+
+ public QualityProfilePage shouldHaveAssociatedProject(String projectName) {
+ Selenide.$(".js-profile-project").shouldHave(Condition.text(projectName));
+ return this;
+ }
+
+ public QualityProfilePage shouldAllowToChangeProjects() {
+ Selenide.$(".js-change-projects").shouldBe(Condition.visible).click();
+ Selenide.$("#profile-projects .select-list-list").shouldBe(Condition.visible);
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RuleDetails.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RuleDetails.java
new file mode 100644
index 00000000000..035a66f3019
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RuleDetails.java
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+
+public class RuleDetails {
+
+ private final SelenideElement elt;
+
+ public RuleDetails(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public RuleDetails shouldBeActivatedOn(String profileName) {
+ Selenide.$("#coding-rules-detail-quality-profiles").shouldHave(Condition.text(profileName));
+ return this;
+ }
+
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RuleItem.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RuleItem.java
new file mode 100644
index 00000000000..7b5d818bc25
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RuleItem.java
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.SelenideElement;
+
+public class RuleItem {
+
+ private final SelenideElement elt;
+
+ public RuleItem(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public SelenideElement getTitle() {
+ return elt.$(".coding-rule-title");
+ }
+
+ public SelenideElement getMetadata() {
+ return elt.$(".coding-rule-meta");
+ }
+
+
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RulesPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RulesPage.java
new file mode 100644
index 00000000000..6b2916e5240
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/RulesPage.java
@@ -0,0 +1,66 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+import org.openqa.selenium.By;
+
+public class RulesPage extends Navigation {
+
+ public RulesPage() {
+ Selenide.$(By.cssSelector(".coding-rules")).should(Condition.exist);
+ }
+
+ public int getTotal() {
+ // warning - number is localized
+ return Integer.parseInt(Selenide.$("#coding-rules-total").text());
+ }
+
+ public ElementsCollection getSelectedFacetItems(String facetName) {
+ SelenideElement facet = Selenide.$(".search-navigator-facet-box[data-property='"+ facetName+"']").shouldBe(Condition.visible);
+ return facet.$$(".js-facet.active");
+ }
+
+ public RulesPage shouldHaveTotalRules(Integer total) {
+ Selenide.$("#coding-rules-total").shouldHave(Condition.text(total.toString()));
+ return this;
+ }
+
+ public RulesPage openFacet(String facet) {
+ Selenide.$(".search-navigator-facet-box[data-property=\"" + facet + "\"] .js-facet-toggle").click();
+ return this;
+ }
+
+ public RulesPage selectFacetItemByText(String facet, String itemText) {
+ Selenide.$$(".search-navigator-facet-box[data-property=\"" + facet + "\"] .js-facet")
+ .findBy(Condition.text(itemText)).click();
+ return this;
+ }
+
+ public RuleDetails openFirstRule() {
+ Selenide.$$(".js-rule").first().click();
+ Selenide.$(".coding-rules-details").shouldBe(Condition.visible);
+ return new RuleDetails(Selenide.$(".coding-rules-details"));
+ }
+
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/SystemInfoPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/SystemInfoPage.java
new file mode 100644
index 00000000000..5b93e2b457a
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/SystemInfoPage.java
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.CollectionCondition;
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+
+public class SystemInfoPage {
+ public SystemInfoPage() {
+ Selenide.$(".page-title").should(Condition.exist).shouldHave(Condition.text("System Info"));
+ }
+
+ public SystemInfoPage shouldHaveCard(String title) {
+ Selenide.$$(".system-info-health-card-title").find(Condition.text(title)).should(Condition.exist);
+ return this;
+ }
+
+ public SystemInfoPage shouldHaveCards(String... titles) {
+ Selenide.$$(".system-info-health-card-title").shouldHave(CollectionCondition.texts(titles));
+ return this;
+ }
+
+ public SystemInfoPageItem getCardItem(String card) {
+ SelenideElement cardTitle = Selenide.$$(".system-info-health-card-title").find(Condition.text(card)).should(Condition.exist);
+ return new SystemInfoPageItem(cardTitle.parent().parent());
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/SystemInfoPageItem.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/SystemInfoPageItem.java
new file mode 100644
index 00000000000..55d9c84092e
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/SystemInfoPageItem.java
@@ -0,0 +1,85 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.SelenideElement;
+
+public class SystemInfoPageItem {
+ private final SelenideElement elt;
+
+ public SystemInfoPageItem(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public SystemInfoPageItem shouldHaveHealth() {
+ elt.$(".system-info-health-info .status-indicator").should(Condition.exist);
+ return this;
+ }
+
+ public SystemInfoPageItem shouldHaveSection(String section) {
+ ensureOpen();
+ elt.$$("h4").findBy(Condition.text(section)).should(Condition.exist);
+ return this;
+ }
+
+ public SystemInfoPageItem shouldNotHaveSection(String section) {
+ ensureOpen();
+ elt.$$("h4").findBy(Condition.text(section)).shouldNot(Condition.exist);
+ return this;
+ }
+
+ public SystemInfoPageItem shouldHaveMainSection() {
+ ensureOpen();
+ elt.$$(".system-info-section").get(0).find("h4").shouldNot(Condition.exist);
+ return this;
+ }
+
+ public SystemInfoPageItem shouldHaveField(String field) {
+ ensureOpen();
+ elt.$$(".system-info-section-item-name").findBy(Condition.text(field)).should(Condition.exist);
+ return this;
+ }
+
+ public SystemInfoPageItem shouldNotHaveField(String field) {
+ ensureOpen();
+ elt.$$(".system-info-section-item-name").findBy(Condition.exactText(field)).shouldNot(Condition.exist);
+ return this;
+ }
+
+ public SystemInfoPageItem shouldHaveFieldWithValue(String field, String value) {
+ ensureOpen();
+ SelenideElement fieldElem = elt.$$(".system-info-section-item-name").findBy(Condition.text(field)).should(Condition.exist);
+ fieldElem.parent().parent().$$("td").shouldHaveSize(2).get(1).shouldHave(Condition.text(value));
+ return this;
+ }
+
+ public SystemInfoPageItem ensureOpen() {
+ if(!isOpen()) {
+ elt.click();
+ elt.$(".boxed-group-inner").should(Condition.exist);
+ }
+ return this;
+ }
+
+ private boolean isOpen() {
+ return elt.$(".boxed-group-inner").exists();
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/issues/Issue.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/issues/Issue.java
new file mode 100644
index 00000000000..d4e2713112e
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/issues/Issue.java
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects.issues;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+
+public class Issue {
+
+ private final SelenideElement elt;
+
+ public Issue(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public Issue shouldAllowAssign() {
+ elt.find(".js-issue-assign").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public Issue shouldAllowChangeType() {
+ elt.find(".js-issue-set-type").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public Issue shouldNotAllowAssign() {
+ elt.find(".js-issue-assign").shouldNotBe(Condition.visible);
+ return this;
+ }
+
+ public Issue shouldNotAllowChangeType() {
+ elt.find(".js-issue-set-type").shouldNotBe(Condition.visible);
+ return this;
+ }
+
+ public Issue assigneeSearchResultCount(String query, Integer count) {
+ SelenideElement assignLink = elt.find(".js-issue-assign");
+ assignLink.click();
+ SelenideElement popupMenu = Selenide.$(".bubble-popup ul.menu").shouldBe(Condition.visible);
+ Selenide.$(".bubble-popup input.search-box-input").shouldBe(Condition.visible).val("").sendKeys(query);
+ popupMenu.$("li a[data-text='Not assigned']").shouldNot(Condition.exist);
+ popupMenu.$$("li").shouldHaveSize(count);
+ assignLink.click();
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/issues/IssuesPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/issues/IssuesPage.java
new file mode 100644
index 00000000000..92755921f37
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/issues/IssuesPage.java
@@ -0,0 +1,82 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects.issues;
+
+import com.codeborne.selenide.CollectionCondition;
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.Selenide;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class IssuesPage {
+
+ public IssuesPage() {
+ Selenide.$(".issues").should(Condition.exist);
+ }
+
+ private ElementsCollection getIssuesElements() {
+ return Selenide.$$(".issues .issue");
+ }
+
+ private ElementsCollection getIssuesPathComponents() {
+ return Selenide.$$(".issues-workspace-list-component");
+ }
+
+ public List<Issue> getIssues() {
+ return getIssuesElements()
+ .stream()
+ .map(Issue::new)
+ .collect(Collectors.toList());
+ }
+
+ public IssuesPage issuesCount(Integer count) {
+ this.getIssuesElements().shouldHaveSize(count);
+ return this;
+ }
+
+ public Issue getFirstIssue() {
+ getIssuesElements().shouldHave(CollectionCondition.sizeGreaterThan(0));
+ return new Issue(getIssuesElements().first());
+ }
+
+ public IssuesPage componentsShouldContain(String path) {
+ this.getIssuesPathComponents().forEach(element -> element.shouldHave(Condition.text(path)));
+ return this;
+ }
+
+ public IssuesPage componentsShouldNotContain(String path) {
+ this.getIssuesPathComponents().forEach(element -> element.shouldNotHave(Condition.text(path)));
+ return this;
+ }
+
+ public IssuesPage bulkChangeOpen() {
+ Selenide.$("#issues-bulk-change").shouldBe(Condition.visible).click();
+ Selenide.$("#bulk-change-form").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public IssuesPage bulkChangeAssigneeSearchCount(String query, Integer count) {
+ Selenide.$("#issues-bulk-change-assignee .Select-input input").val(query);
+ Selenide.$$("#issues-bulk-change-assignee .Select-option").shouldHaveSize(count);
+ Selenide.$("#issues-bulk-change-assignee .Select-input input").pressEscape();
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/measures/MeasureContent.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/measures/MeasureContent.java
new file mode 100644
index 00000000000..4f3da0472e5
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/measures/MeasureContent.java
@@ -0,0 +1,61 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects.measures;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.SelenideElement;
+
+public class MeasureContent {
+ private final SelenideElement elt;
+
+ public MeasureContent(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public MeasureContent shouldHaveTitle(String title) {
+ this.elt.$(".measure-details-header .measure-details-metric").should(Condition.exist).shouldHave(Condition.text(title));
+ return this;
+ }
+
+ public MeasureContent shouldHaveHeaderValue(String value) {
+ this.elt.$(".measure-details-header .measure-details-value").should(Condition.exist).shouldHave(Condition.text(value));
+ return this;
+ }
+
+ public MeasureContent shouldHaveFile(String path) {
+ this.getFiles().find(Condition.text(path)).should(Condition.exist);
+ return this;
+ }
+
+ public MeasureContent drillDown(String item) {
+ this.getFiles().find(Condition.text(item)).should(Condition.exist).find("a").click();
+ return this;
+ }
+
+ public MeasureContent shouldDisplayCode() {
+ this.elt.$(".source-line-code").should(Condition.exist);
+ return this;
+ }
+
+ private ElementsCollection getFiles() {
+ return this.elt.$$(".measure-details-component-row");
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/measures/MeasuresPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/measures/MeasuresPage.java
new file mode 100644
index 00000000000..de052a403de
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/measures/MeasuresPage.java
@@ -0,0 +1,97 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects.measures;
+
+import com.codeborne.selenide.CollectionCondition;
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+import org.openqa.selenium.Keys;
+
+public class MeasuresPage {
+ public MeasuresPage() {
+ Selenide.$("#component-measures").should(Condition.exist);
+ }
+
+ public MeasuresPage displayBubbleChart(String title) {
+ SelenideElement bubblechart = Selenide.$("#component-measures .measure-overview-bubble-chart");
+ bubblechart.$(".measure-overview-bubble-chart-title").shouldHave(Condition.text(title));
+ return this;
+ }
+
+ public MeasuresPage measureHasValue(String measure, Integer value) {
+ SelenideElement sidebar = this.getSideBar();
+ sidebar.$("#measure-" + measure + "-name").should(Condition.exist);
+ sidebar.$("#measure-" + measure + "-value").should(Condition.exist).shouldHave(Condition.text(value.toString()));
+ return this;
+ }
+
+ public MeasuresPage measureHasLeak(String measure, Integer value) {
+ SelenideElement sidebar = this.getSideBar();
+ sidebar.$("#measure-" + measure + "-name").should(Condition.exist);
+ sidebar.$("#measure-" + measure + "-leak").should(Condition.exist).shouldHave(Condition.text(value.toString()));
+ return this;
+ }
+
+ public MeasuresPage breadcrumbsShouldHave(String item) {
+ Selenide.$(".layout-page-header-panel .measure-breadcrumbs").shouldHave(Condition.text(item));
+ return this;
+ }
+
+ public MeasuresPage breadcrumbsShouldNotHave(String item) {
+ Selenide.$(".layout-page-header-panel .measure-breadcrumbs").shouldNotHave(Condition.text(item));
+ return this;
+ }
+
+ public MeasuresPage backShortcut() {
+ Selenide.$(".layout-page-header-panel").sendKeys(Keys.LEFT);
+ return this;
+ }
+
+ public MeasuresPage switchView(String view) {
+ SelenideElement select = Selenide.$(".measure-view-select").should(Condition.exist);
+ select.click();
+ select.$(".Select-menu-outer").should(Condition.exist)
+ .$$(".Select-option").shouldHave(CollectionCondition.sizeGreaterThan(1))
+ .find(Condition.text(view)).should(Condition.exist).click();
+ return this;
+ }
+
+ public MeasuresPage openFacet(String facet) {
+ SelenideElement facetBox = Selenide.$$(".search-navigator-facet-box").find(Condition.text(facet));
+ if(!facetBox.find("search-navigator-facet-list").isDisplayed()) {
+ facetBox.$(".search-navigator-facet-header a").should(Condition.exist).click();
+ }
+ return this;
+ }
+
+ public MeasureContent openMeasureContent(String measure) {
+ SelenideElement sidebar = this.getSideBar();
+ SelenideElement facetItem = sidebar.$("#measure-" + measure + "-name");
+ facetItem.click();
+ MeasureContent content = new MeasureContent(Selenide.$("#component-measures .measure-details-content").should(Condition.exist));
+ content.shouldHaveTitle(facetItem.getText());
+ return content;
+ }
+
+ private SelenideElement getSideBar() {
+ return Selenide.$("#component-measures .layout-page-side").should(Condition.exist);
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/organization/MemberItem.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/organization/MemberItem.java
new file mode 100644
index 00000000000..fd02dfb1f11
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/organization/MemberItem.java
@@ -0,0 +1,94 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonarqube.qa.util.pageobjects.organization;
+
+import com.codeborne.selenide.CollectionCondition;
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+
+public class MemberItem {
+ private final SelenideElement elt;
+
+ public MemberItem(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public MemberItem shouldBeNamed(String login, String name) {
+ ElementsCollection tds = this.elt.$$("td");
+ tds.get(1).$("strong").shouldHave(Condition.text(name));
+ tds.get(1).$("span").shouldHave(Condition.text(login));
+ return this;
+ }
+
+ public MemberItem shouldHaveGroups(Integer groups) {
+ ElementsCollection tds = this.elt.$$("td");
+ tds.get(2).should(Condition.exist);
+ tds.get(2).shouldHave(Condition.text(groups.toString()));
+ return this;
+ }
+
+ public MemberItem shouldNotHaveActions() {
+ this.elt.$$("td").shouldHave(CollectionCondition.sizeLessThan(3));
+ return this;
+ }
+
+ public MemberItem removeMembership() {
+ ElementsCollection tds = this.elt.$$("td");
+ tds.shouldHave(CollectionCondition.sizeGreaterThan(3));
+ SelenideElement actionTd = tds.get(3);
+ actionTd.$("button").should(Condition.exist).click();
+ actionTd.$$(".dropdown-menu > li").get(2).shouldBe(Condition.visible).click();
+ SelenideElement modal = getModal("Remove user");
+ modal.$("button.button-red").shouldBe(Condition.visible).click();
+ return this;
+ }
+
+ public MemberItem manageGroupsOpen() {
+ ElementsCollection tds = this.elt.$$("td");
+ tds.shouldHave(CollectionCondition.sizeGreaterThan(3));
+ SelenideElement actionTd = tds.get(3);
+ actionTd.$("button").should(Condition.exist).click();
+ actionTd.$$(".dropdown-menu > li").get(0).shouldBe(Condition.visible).click();
+ getModal("Manage groups");
+ return this;
+ }
+
+ public MemberItem manageGroupsSelect(String group) {
+ SelenideElement modal = getModal("Manage groups");
+ modal.$$("li").find(Condition.text(group)).shouldBe(Condition.visible).click();
+ return this;
+ }
+
+ public MemberItem manageGroupsSave() {
+ SelenideElement modal = getModal("Manage groups");
+ modal.$("button[type='submit']").shouldBe(Condition.visible).click();
+ return this;
+ }
+
+ private SelenideElement getModal(String title) {
+ Selenide.$(".modal-head").should(Condition.exist).shouldHave(Condition.text(title));
+ SelenideElement form = Selenide.$(".ReactModalPortal form");
+ form.should(Condition.exist);
+ return form;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/organization/MembersPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/organization/MembersPage.java
new file mode 100644
index 00000000000..21816aea1c1
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/organization/MembersPage.java
@@ -0,0 +1,81 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonarqube.qa.util.pageobjects.organization;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+
+public class MembersPage {
+
+ public MembersPage() {
+ Selenide.$(".navbar-tabs a.active").shouldBe(Condition.visible).shouldHave(Condition.text("Members"));
+ }
+
+ public ElementsCollection getMembers() {
+ return Selenide.$$("table.data tr");
+ }
+
+ public MemberItem getMembersByIdx(Integer idx) {
+ return new MemberItem(getMembers().get(idx));
+ }
+
+ public MembersPage shouldHaveTotal(int total) {
+ Selenide.$(".panel-vertical > span > strong").shouldHave(Condition.text(String.valueOf(total)));
+ return this;
+ }
+
+ public MembersPage searchForMember(String query) {
+ Selenide.$(".page .search-box-input").shouldBe(Condition.visible).val("").sendKeys(query);
+ return this;
+ }
+
+ public MembersPage canAddMember() {
+ Selenide.$(".page-actions").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public MembersPage canNotAddMember() {
+ Selenide.$(".page-actions").shouldNot(Condition.exist);
+ return this;
+ }
+
+ public MembersPage addMember(String login) {
+ this.canAddMember();
+ Selenide.$(".page-actions button").click();
+
+ SelenideElement modal = this.getModal("Add user");
+ SelenideElement input = modal.$(".Select-input input");
+ input.val(login);
+ modal.$("div.Select-option.is-focused").should(Condition.exist);
+ input.pressEnter();
+ modal.$("button[type='submit']").click();
+ return this;
+ }
+
+ private SelenideElement getModal(String title) {
+ Selenide.$(".modal-head").should(Condition.exist).shouldHave(Condition.text(title));
+ SelenideElement form = Selenide.$(".ReactModalPortal form");
+ form.should(Condition.exist);
+ return form;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/package-info.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/package-info.java
new file mode 100644
index 00000000000..bc9f94356e3
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonarqube.qa.util.pageobjects;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/FacetItem.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/FacetItem.java
new file mode 100644
index 00000000000..74425419c26
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/FacetItem.java
@@ -0,0 +1,49 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects.projects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.SelenideElement;
+
+public class FacetItem {
+
+ private final SelenideElement elt;
+
+ public FacetItem(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public FacetItem shouldHaveValue(String key, String value) {
+ this.elt.$(".facet[data-key=\"" + key + "\"] .facet-stat").shouldHave(Condition.text(value));
+ return this;
+ }
+
+ public void selectValue(String key) {
+ this.elt.$(".facet[data-key=\"" + key + "\"]").click();
+ }
+
+ public FacetItem selectOptionItem(String value) {
+ SelenideElement selectInput = this.elt.$(".Select-input input");
+ selectInput.val(value);
+ this.elt.$("div.Select-option.is-focused").should(Condition.exist);
+ selectInput.pressEnter();
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/ProjectItem.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/ProjectItem.java
new file mode 100644
index 00000000000..45ef2cb62ec
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/ProjectItem.java
@@ -0,0 +1,37 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects.projects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.SelenideElement;
+
+public class ProjectItem {
+
+ private final SelenideElement elt;
+
+ public ProjectItem(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public ProjectItem shouldHaveMeasure(String metricKey, String value) {
+ this.elt.$(".project-card-measure[data-key=\"" + metricKey + "\"]").shouldHave(Condition.text(value));
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/ProjectsPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/ProjectsPage.java
new file mode 100644
index 00000000000..cc55ce2d619
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/projects/ProjectsPage.java
@@ -0,0 +1,116 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects.projects;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+import com.codeborne.selenide.WebDriverRunner;
+import org.assertj.core.api.Assertions;
+
+public class ProjectsPage {
+
+ public ProjectsPage() {
+ Selenide.$("#projects-page").shouldBe(Condition.visible);
+ }
+
+ public ElementsCollection getProjects() {
+ return Selenide.$$(".projects-list > .boxed-group");
+ }
+
+ public ElementsCollection getFacets() {
+ return Selenide.$$(".search-navigator-facet-box");
+ }
+
+ public ProjectItem getProjectByKey(String projectKey) {
+ SelenideElement element = getProjects().find(Condition.attribute("data-key", projectKey));
+ return new ProjectItem(element);
+ }
+
+ public ProjectItem getProjectByIdx(Integer idx) {
+ return new ProjectItem(getProjects().get(idx));
+ }
+
+ public FacetItem getFacetByProperty(String facetProperty) {
+ SelenideElement element = getFacets().find(Condition.attribute("data-key", facetProperty));
+ return new FacetItem(element);
+ }
+
+ public ProjectsPage shouldHaveTotal(int total) {
+ // warning - number is localized
+ Selenide.$("#projects-total").shouldHave(Condition.text(String.valueOf(total)));
+ return this;
+ }
+
+ public ProjectsPage shouldDisplayAllProjects() {
+ Assertions.assertThat(WebDriverRunner.url()).endsWith("/projects");
+ return this;
+ }
+
+ public ProjectsPage shouldDisplayAllProjectsWidthSort(String sort) {
+ Assertions.assertThat(WebDriverRunner.url()).endsWith("/projects?sort=" + sort);
+ return this;
+ }
+
+ public ProjectsPage shouldDisplayFavoriteProjects() {
+ Assertions.assertThat(WebDriverRunner.url()).endsWith("/projects/favorite");
+ return this;
+ }
+
+ public ProjectsPage selectAllProjects() {
+ Selenide.$("#all-projects").click();
+ return shouldDisplayAllProjects();
+ }
+
+ public ProjectsPage selectFavoriteProjects() {
+ Selenide.$("#favorite-projects").click();
+ return shouldDisplayFavoriteProjects();
+ }
+
+ public ProjectsPage searchProject(String search) {
+ SelenideElement searchInput = Selenide.$(".projects-topbar-item-search input");
+ searchInput.setValue("").sendKeys(search);
+ return this;
+ }
+
+ public ProjectsPage changePerspective(String perspective) {
+ SelenideElement sortSelect = getOpenTopBar().$(".js-projects-perspective-select");
+ sortSelect.$(".Select-value").should(Condition.exist).click();
+ sortSelect.$(".Select-option[title='" + perspective + "']").should(Condition.exist).click();
+ return this;
+ }
+
+ public ProjectsPage sortProjects(String sort) {
+ SelenideElement sortSelect = getOpenTopBar().$(".js-projects-sorting-select");
+ sortSelect.$(".Select-value").should(Condition.exist).click();
+ sortSelect.$(".Select-option[title='" + sort + "']").should(Condition.exist).click();
+ return this;
+ }
+
+ public ProjectsPage invertSorting() {
+ getOpenTopBar().$(".js-projects-sorting-invert").should(Condition.exist).click();
+ return this;
+ }
+
+ private SelenideElement getOpenTopBar() {
+ return Selenide.$(".projects-topbar-items").should(Condition.exist);
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/settings/PropertySetInput.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/settings/PropertySetInput.java
new file mode 100644
index 00000000000..fb5de082a9c
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/settings/PropertySetInput.java
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects.settings;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.SelenideElement;
+
+public class PropertySetInput {
+
+ private final SelenideElement elt;
+
+ public PropertySetInput(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public PropertySetInput setFieldValue(int index, String fieldKey, String value) {
+ elt.findAll("input[name$=\"[" + fieldKey + "]\"]").get(index).val(value);
+ return this;
+ }
+
+ public PropertySetInput setFieldValue(String fieldKey, String value) {
+ return setFieldValue(0, fieldKey, value);
+ }
+
+ public PropertySetInput save() {
+ elt.find(".js-save-changes").click();
+ elt.find(".js-save-changes").shouldNot(Condition.exist);
+ return this;
+ }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/settings/SettingsPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/settings/SettingsPage.java
new file mode 100644
index 00000000000..1bc4e646d5d
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/settings/SettingsPage.java
@@ -0,0 +1,80 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.qa.util.pageobjects.settings;
+
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.Selenide;
+import com.codeborne.selenide.SelenideElement;
+import org.openqa.selenium.By;
+
+public class SettingsPage {
+
+ public SettingsPage() {
+ Selenide.$("#settings-page").shouldBe(Condition.visible);
+ }
+
+ public SettingsPage assertMenuContains(String categoryName) {
+ Selenide.$(".side-tabs-menu").$(By.linkText(categoryName)).shouldBe(Condition.visible);
+ return this;
+ }
+
+ public SettingsPage assertSettingDisplayed(String settingKey) {
+ Selenide.$(".settings-definition[data-key='" + settingKey + "']").shouldBe(Condition.visible);
+ return this;
+ }
+
+ public SettingsPage assertSettingNotDisplayed(String settingKey) {
+ Selenide.$(".settings-definition[data-key='" + settingKey + "']").shouldNotBe(Condition.visible);
+ return this;
+ }
+
+ public SettingsPage openCategory(String categoryName) {
+ Selenide.$(".side-tabs-menu").$(By.linkText(categoryName)).click();
+ return this;
+ }
+
+ public SettingsPage assertStringSettingValue(String settingKey, String value) {
+ Selenide.$("input[name=\"settings[" + settingKey + "]\"]").shouldHave(Condition.exactValue(value));
+ return this;
+ }
+
+ public SettingsPage assertBooleanSettingValue(String settingKey, boolean value) {
+ SelenideElement toggle = Selenide.$("button[name=\"settings[" + settingKey + "]\"]");
+ if (value) {
+ toggle.shouldHave(Condition.cssClass("boolean-toggle-on"));
+ } else {
+ toggle.shouldNotHave(Condition.cssClass("boolean-toggle-on"));
+ }
+ return this;
+ }
+
+ public SettingsPage setStringValue(String settingKey, String value) {
+ SelenideElement setting = Selenide.$(".settings-definition[data-key=\"" + settingKey + "\"]");
+ setting.find("input").val(value);
+ setting.find(".js-save-changes").click();
+ setting.find(".js-save-changes").shouldNot(Condition.exist);
+ return this;
+ }
+
+ public PropertySetInput getPropertySetInput(String settingKey) {
+ SelenideElement setting = Selenide.$(".settings-definition[data-key=\"" + settingKey + "\"]");
+ return new PropertySetInput(setting);
+ }
+}