]> source.dussan.org Git - sonarqube.git/commitdiff
Update users permission IT's
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 20 Nov 2017 11:36:09 +0000 (12:36 +0100)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Fri, 24 Nov 2017 16:22:33 +0000 (17:22 +0100)
server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java
server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/UsersManagementItem.java [new file with mode: 0644]
server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/UsersManagementPage.java [new file with mode: 0644]
tests/src/test/java/org/sonarqube/tests/user/RealmAuthenticationTest.java
tests/src/test/java/org/sonarqube/tests/user/UsersPageTest.java
tests/src/test/resources/user/ExternalAuthenticationTest/create-and-delete-user.html [deleted file]
tests/src/test/resources/user/UsersPageTest/admin_should_change_its_own_password.html [deleted file]
tests/src/test/resources/user/UsersPageTest/generate_and_revoke_user_token.html [deleted file]

index 25fc6937c8eae8dea51182ffab9a0eca7cc670c8..996f46d35576d30757a0463b009c095af2cd4478 100644 (file)
@@ -178,6 +178,10 @@ public class Navigation {
     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);
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/UsersManagementItem.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/UsersManagementItem.java
new file mode 100644 (file)
index 0000000..0cd6365
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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));
+  }
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/UsersManagementPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/UsersManagementPage.java
new file mode 100644 (file)
index 0000000..efc2edf
--- /dev/null
@@ -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.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;
+  }
+}
index 686732cb34078ddd27ff50dec4897a855c6f9082..a99d247263cf73fe844dc7cec57d86b3b44d69e3 100644 (file)
@@ -19,6 +19,7 @@
  */
 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;
@@ -37,7 +38,9 @@ import org.sonar.wsclient.connectors.HttpClient4Connector;
 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;
@@ -233,7 +236,17 @@ public class RealmAuthenticationTest {
     // 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;
index 38b62681a9cc2738b136c6e7157995d2d9f3436e..2aa83ffae749bd02872d6518a2d598952460e74d 100644 (file)
 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;
@@ -47,38 +48,54 @@ public class UsersPageTest {
   @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);
   }
 }
diff --git a/tests/src/test/resources/user/ExternalAuthenticationTest/create-and-delete-user.html b/tests/src/test/resources/user/ExternalAuthenticationTest/create-and-delete-user.html
deleted file mode 100644 (file)
index 9be06a9..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-<?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=&quot;${userId}&quot;] .dropdown-toggle</td>
-       <td></td>
-</tr>
-<tr>
-       <td>click</td>
-       <td>css=[data-login=&quot;${userId}&quot;] .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>
diff --git a/tests/src/test/resources/user/UsersPageTest/admin_should_change_its_own_password.html b/tests/src/test/resources/user/UsersPageTest/admin_should_change_its_own_password.html
deleted file mode 100644 (file)
index 228686f..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-<?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>
diff --git a/tests/src/test/resources/user/UsersPageTest/generate_and_revoke_user_token.html b/tests/src/test/resources/user/UsersPageTest/generate_and_revoke_user_token.html
deleted file mode 100644 (file)
index 1c816cb..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-<?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>