return open("/account/notifications", NotificationsPage.class);
}
+ public UsersManagementPage openUsersManagement() {
+ return open("/admin/users", UsersManagementPage.class);
+ }
+
public ProjectPermissionsPage openProjectPermissions(String projectKey) {
String url = "/project_roles?id=" + escape(projectKey);
return open(url, ProjectPermissionsPage.class);
--- /dev/null
+/*
+ * 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;
+
+import static com.codeborne.selenide.Selenide.$;
+import static com.codeborne.selenide.Selenide.$$;
+
+public class UsersManagementItem {
+ private final SelenideElement elt;
+
+ public UsersManagementItem(SelenideElement elt) {
+ this.elt = elt;
+ }
+
+ public UsersManagementItem hasTokensCount(Integer count) {
+ this.elt.$(".js-user-tokens").should(Condition.exist).parent().shouldHave(Condition.text(count.toString()));
+ return this;
+ }
+
+ public UsersManagementItem generateToken(String name) {
+ this.openTokenModal();
+ $(".modal #generate-token-form input").should(Condition.exist).sendKeys(name);
+ $(".modal #generate-token-form .js-generate-token").should(Condition.exist).click();
+ $(".modal code").should(Condition.exist);
+ getTokenRow(name).should(Condition.exist);
+ closeModal();
+ return this;
+ }
+
+ public UsersManagementItem revokeToken(String name) {
+ this.openTokenModal();
+ SelenideElement tokenRow = getTokenRow(name).should(Condition.exist);
+ tokenRow.$("button").should(Condition.exist).shouldHave(Condition.text("Revoke")).click();
+ tokenRow.$("button").shouldHave(Condition.text("Sure?")).click();
+ getTokenRow(name).shouldNot(Condition.exist);
+ closeModal();
+ return this;
+ }
+
+ public UsersManagementItem changePassword(String oldPwd, String newPwd) {
+ this.elt.$("button.dropdown-toggle").should(Condition.exist).click();
+ this.elt.$(".js-user-change-password").shouldBe(Condition.visible).click();
+ isModalOpen("Change password");
+ $(".modal #old-user-password").should(Condition.exist).sendKeys(oldPwd);
+ $(".modal #user-password").should(Condition.exist).sendKeys(newPwd);
+ $(".modal #confirm-user-password").should(Condition.exist).sendKeys(newPwd);
+ $(".modal .js-confirm").click();
+ $(".modal").shouldNot(Condition.exist);
+ return this;
+ }
+
+ public UsersManagementItem deactivateUser() {
+ this.elt.$("button.dropdown-toggle").should(Condition.exist).click();
+ this.elt.$(".js-user-deactivate").should(Condition.exist).click();
+ isModalOpen("Deactivate User");
+ $(".modal .js-confirm").should(Condition.exist).click();
+ return this;
+ }
+
+ private void openTokenModal() {
+ if (!$(".modal").exists()) {
+ this.elt.$(".js-user-tokens").should(Condition.exist).click();
+ }
+ isModalOpen("Tokens");
+ }
+
+ private static void closeModal() {
+ $(".modal .js-modal-close").should(Condition.exist).click();
+ }
+
+ private static void isModalOpen(String title) {
+ $(".modal .modal-head").should(Condition.exist).shouldHave(Condition.text(title));
+ }
+
+ private static SelenideElement getTokenRow(String name) {
+ return $$(".modal tr").findBy(Condition.text(name));
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+import static com.codeborne.selenide.Selenide.$;
+import static com.codeborne.selenide.Selenide.$$;
+
+public class UsersManagementPage {
+ public UsersManagementPage() {
+ $("#users-page").shouldBe(Condition.visible);
+ }
+
+ public UsersManagementPage hasUsersCount(Integer count) {
+ $$(".js-user-login").shouldHaveSize(count);
+ return this;
+ }
+
+ public UsersManagementItem getUser(String login) {
+ SelenideElement elt = $$(".js-user-login").findBy(Condition.text(login)).should(Condition.exist);
+ return new UsersManagementItem(elt.parent().parent().parent());
+ }
+
+ public UsersManagementPage createUser(String login) {
+ $("#users-create").should(Condition.exist).click();
+ $(".modal .modal-head").should(Condition.exist).shouldHave(Condition.text("Create User"));
+ $(".modal #create-user-login").should(Condition.exist).sendKeys(login);
+ $(".modal #create-user-name").should(Condition.exist).sendKeys("Name of " + login);
+ $(".modal #create-user-password").should(Condition.exist).sendKeys(login);
+ $(".modal .js-confirm").should(Condition.exist).click();
+ return this;
+ }
+}
*/
package org.sonarqube.tests.user;
+import com.codeborne.selenide.Condition;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.sonar.orchestrator.Orchestrator;
import org.sonar.wsclient.services.AuthenticationQuery;
import org.sonar.wsclient.user.UserParameters;
import org.sonarqube.qa.util.Tester;
+import org.sonarqube.qa.util.pageobjects.Navigation;
import org.sonarqube.qa.util.pageobjects.SystemInfoPage;
+import org.sonarqube.qa.util.pageobjects.UsersManagementPage;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.WsResponse;
import org.sonarqube.ws.client.user.CreateRequest;
// Given clean Sonar installation and no users in external system
// Let's create and delete the user "tester" in Sonar DB
- runSelenese(orchestrator, "/user/ExternalAuthenticationTest/create-and-delete-user.html");
+ Navigation nav = tester.openBrowser();
+ UsersManagementPage page = nav.logIn().submitCredentials(ADMIN_USER_LOGIN).openUsersManagement();
+ page
+ .createUser(USER_LOGIN)
+ .hasUsersCount(3)
+ .getUser(USER_LOGIN)
+ .deactivateUser();
+ page.hasUsersCount(2);
+ nav.logOut()
+ .logIn().submitWrongCredentials(USER_LOGIN, USER_LOGIN)
+ .getErrorMessage().shouldHave(Condition.text("Authentication failed"));
// And now update the security with the user that was deleted
String login = USER_LOGIN;
package org.sonarqube.tests.user;
import com.sonar.orchestrator.Orchestrator;
+import org.junit.After;
+import org.sonarqube.ws.Users.CreateWsResponse.User;
+import org.sonarqube.qa.util.Tester;
+import org.sonarqube.qa.util.pageobjects.UsersManagementPage;
import org.sonarqube.tests.Category1Suite;
import java.util.List;
-import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.sonarqube.ws.Users;
-import org.sonarqube.ws.client.WsClient;
import org.sonarqube.ws.client.user.GroupsRequest;
-import util.selenium.Selenese;
import util.user.UserRule;
+
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
-import static util.ItUtils.newAdminWsClient;
public class UsersPageTest {
- private static final String ADMIN_USER_LOGIN = "admin-user";
+ private User adminUser;
@ClassRule
public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR;
@Rule
public UserRule userRule = UserRule.from(orchestrator);
- private WsClient adminClient = newAdminWsClient(orchestrator);
+ @Rule
+ public Tester tester = new Tester(orchestrator).disableOrganizations();
@Before
- public void initAdminUser() throws Exception {
- userRule.createAdminUser(ADMIN_USER_LOGIN, ADMIN_USER_LOGIN);
+ public void initUsers() throws Exception {
+ adminUser = tester.users().generateAdministrator(u -> u.setLogin("admin-user").setPassword("admin-user"));
+ tester.users().generate(u -> u.setLogin("random-user").setPassword("random-user"));
}
@After
- public void deleteAdminUser() {
+ public void resetUsers() {
userRule.resetUsers();
}
@Test
public void generate_and_revoke_user_token() {
- Selenese.runSelenese(orchestrator, "/user/UsersPageTest/generate_and_revoke_user_token.html");
+ UsersManagementPage page = tester.openBrowser().logIn().submitCredentials(adminUser.getLogin()).openUsersManagement();
+ tester.wsClient().users().skipOnboardingTutorial();
+
+ page
+ .hasUsersCount(3)
+ .getUser(adminUser.getLogin())
+ .hasTokensCount(0)
+ .generateToken("token-test")
+ .hasTokensCount(1)
+ .revokeToken("token-test")
+ .hasTokensCount(0);
}
@Test
public void admin_should_change_his_own_password() {
- Selenese.runSelenese(orchestrator, "/user/UsersPageTest/admin_should_change_its_own_password.html");
+ UsersManagementPage page = tester.openBrowser().logIn().submitCredentials(adminUser.getLogin()).openUsersManagement();
+ tester.wsClient().users().skipOnboardingTutorial();
+ page
+ .hasUsersCount(3)
+ .getUser(adminUser.getLogin())
+ .changePassword(adminUser.getLogin(), "newpassword");
}
@Test
public void return_groups_belonging_to_a_user() {
String login = randomAlphabetic(10);
String group = randomAlphabetic(10);
- userRule.createUser(login, login);
- userRule.createGroup(group);
- userRule.associateGroupsToUser(login, group);
-
- List<Users.GroupsWsResponse.Group> result = adminClient.users().groups(GroupsRequest.builder().setLogin(login).build()).getGroupsList();
+ tester.users().generate(u -> u.setLogin(login).setPassword(login));
+ tester.groups().generate(null, g -> g.setName(group));
+ tester.groups().addMemberToGroups(tester.organizations().getDefaultOrganization(), login, group);
+ List<Users.GroupsWsResponse.Group> result = tester.as(adminUser.getLogin()).wsClient().users().groups(GroupsRequest.builder().setLogin(login).build()).getGroupsList();
assertThat(result).extracting(Users.GroupsWsResponse.Group::getName).contains(group);
}
}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-/W3C/DTD XHTML 1.0 Strict/EN" "http:/www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http:/www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http:/selenium-ide.openqa.org/profiles/test-case">
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- <title>create-and-delete-users</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
- <thead>
- <tr>
- <td rowspan="1" colspan="3">create-and-delete-users</td>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>open</td>
- <td>/sessions/new</td>
- <td></td>
-</tr>
-<tr>
- <td>type</td>
- <td>login</td>
- <td>admin-user</td>
-</tr>
-<tr>
- <td>type</td>
- <td>password</td>
- <td>admin-user</td>
-</tr>
-<tr>
- <td>clickAndWait</td>
- <td>commit</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=.js-user-authenticated</td>
- <td></td>
-</tr>
-<tr>
- <td>open</td>
- <td>/users</td>
- <td></td>
-</tr>
-<tr>
- <td>store</td>
- <td>javascript{new Date().getTime()}</td>
- <td>userId</td>
-</tr>
-<tr>
- <td>waitForText</td>
- <td>content</td>
- <td>*Create User*</td>
-</tr>
-<tr>
- <td>click</td>
- <td>id=users-create</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForText</td>
- <td>id=create-user-form</td>
- <td>*Create User*</td>
-</tr>
-<tr>
- <td>type</td>
- <td>id=create-user-login</td>
- <td>${userId}</td>
-</tr>
-<tr>
- <td>type</td>
- <td>id=create-user-name</td>
- <td>Name of ${userId}</td>
-</tr>
-<tr>
- <td>type</td>
- <td>id=create-user-password</td>
- <td>password</td>
-</tr>
-<tr>
- <td>click</td>
- <td>id=create-user-submit</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForText</td>
- <td>id=users-list</td>
- <td>*${userId}*</td>
-</tr>
-<tr>
- <td>click</td>
- <td>css=[data-login="${userId}"] .dropdown-toggle</td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>css=[data-login="${userId}"] .js-user-deactivate</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForText</td>
- <td>id=deactivate-user-form</td>
- <td>*${userId}*</td>
-</tr>
-<tr>
- <td>click</td>
- <td>id=deactivate-user-submit</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForNotText</td>
- <td>id=users-list</td>
- <td>*${userId}*</td>
-</tr>
-<tr>
- <td>open</td>
- <td>/sessions/logout</td>
- <td></td>
-</tr>
-<tr>
- <td>open</td>
- <td>/sessions/new</td>
- <td></td>
-</tr>
-<tr>
- <td>type</td>
- <td>login</td>
- <td>tester</td>
-</tr>
-<tr>
- <td>type</td>
- <td>password</td>
- <td>password</td>
-</tr>
-<tr>
- <td>clickAndWait</td>
- <td>commit</td>
- <td>deactivate-user-form</td>
-</tr>
-<tr>
- <td>waitForText</td>
- <td>login_form</td>
- <td>*Authentication failed*</td>
-</tr>
-</tbody>
-</table>
-</body>
-</html>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- <link rel="selenium.base" href="http://localhost:49506"/>
- <title>admin_should_change_its_own_password</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr>
-<td rowspan="1" colspan="3">admin_should_change_its_own_password</td>
-</tr>
-</thead>
-<tbody>
-
-<tr>
- <td>open</td>
- <td>/sessions/login</td>
- <td></td>
-</tr>
-<tr>
- <td>type</td>
- <td>login</td>
- <td>admin-user</td>
-</tr>
-<tr>
- <td>type</td>
- <td>password</td>
- <td>admin-user</td>
-</tr>
-<tr>
- <td>clickAndWait</td>
- <td>commit</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=.js-user-authenticated</td>
- <td></td>
-</tr>
-<tr>
- <td>open</td>
- <td>/users</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=[data-login=admin-user]</td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>css=[data-login=admin-user] .dropdown-toggle</td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>css=[data-login=admin-user] .js-user-change-password</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=.modal</td>
- <td></td>
-</tr>
-<tr>
- <td>type</td>
- <td>id=change-user-password-old-password</td>
- <td>admin-user</td>
-</tr>
-<tr>
- <td>type</td>
- <td>id=change-user-password-password</td>
- <td>new-admin-user</td>
-</tr>
-<tr>
- <td>type</td>
- <td>id=change-user-password-password-confirmation</td>
- <td>new-admin-user</td>
-</tr>
-<tr>
- <td>click</td>
- <td>id=change-user-password-submit</td>
- <td></td>
-</tr>
-<tr>
- <td>assertElementNotPresent</td>
- <td>css=.modal</td>
- <td></td>
-</tr>
-</tbody>
-</table>
-</body>
-</html>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- <link rel="selenium.base" href="http://localhost:49506"/>
- <title>generate_and_revoke_user_token</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
- <thead>
- <tr>
- <td rowspan="1" colspan="3">generate_and_revoke_user_token</td>
- </tr>
- </thead>
- <tbody>
-
-<tr>
- <td>open</td>
- <td>/sessions/new</td>
- <td></td>
-</tr>
-<tr>
- <td>type</td>
- <td>login</td>
- <td>admin-user</td>
-</tr>
-<tr>
- <td>type</td>
- <td>password</td>
- <td>admin-user</td>
-</tr>
-<tr>
- <td>clickAndWait</td>
- <td>commit</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=.js-user-authenticated</td>
- <td></td>
-</tr>
-<tr>
- <td>open</td>
- <td>/users</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=.js-user-tokens</td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>css=.js-user-tokens</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForText</td>
- <td>css=.modal</td>
- <td>*No tokens*</td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=.js-generate-token-form input</td>
- <td></td>
-</tr>
-<tr>
- <td>type</td>
- <td>css=.js-generate-token-form input</td>
- <td>test-token</td>
-</tr>
-<tr>
- <td>click</td>
- <td>css=.js-generate-token-form button</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=.modal code</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForText</td>
- <td>css=.modal</td>
- <td>*test-token*</td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=.js-revoke-token-form</td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>css=.js-revoke-token-form button</td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>css=.js-revoke-token-form button</td>
- <td></td>
-</tr>
-<tr>
- <td>assertElementNotPresent</td>
- <td>css=.js-revoke-token-form</td>
- <td></td>
-</tr>
-</tbody>
-</table>
-</body>
-</html>