@After
public void removeUserAndCleanPluginProperties() throws Exception {
- Optional<Users.User> user = userRule.getUserByLogin(USER_LOGIN);
- if (user.isPresent()) {
- userRule.deactivateUsers(user.get());
- }
+ userRule.deactivateUsers(USER_LOGIN);
setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.enabled", null);
setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.user", null);
}
import com.sonar.orchestrator.build.BuildResult;
import com.sonar.orchestrator.build.SonarRunner;
import com.sonar.orchestrator.locator.FileLocation;
+import com.sonar.orchestrator.selenium.Selenese;
import it.Category4Suite;
+import java.io.IOException;
import java.util.UUID;
import org.junit.After;
import org.junit.AfterClass;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.HttpConnector;
import org.sonarqube.ws.client.HttpWsClient;
-import org.sonarqube.ws.client.PostRequest;
import org.sonarqube.ws.client.WsClient;
import org.sonarqube.ws.client.WsResponse;
import org.sonarqube.ws.client.permission.AddGroupWsRequest;
import org.sonarqube.ws.client.usertoken.RevokeWsRequest;
import org.sonarqube.ws.client.usertoken.SearchWsRequest;
import org.sonarqube.ws.client.usertoken.UserTokensService;
+import util.selenium.SeleneseTest;
+import util.user.UserRule;
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static util.ItUtils.setServerProperty;
public class LocalAuthenticationTest {
+
@ClassRule
public static Orchestrator ORCHESTRATOR = Category4Suite.ORCHESTRATOR;
+
+ @ClassRule
+ public static UserRule userRule = UserRule.from(ORCHESTRATOR);
+
private static WsClient adminWsClient;
private static UserTokensService userTokensWsClient;
userTokensWsClient = adminWsClient.userTokens();
removeGroupPermission("anyone", "scan");
- createUser(LOGIN, "123456");
+ userRule.createUser(LOGIN, "123456");
addUserPermission(LOGIN, "admin");
addUserPermission(LOGIN, "scan");
}
@AfterClass
- public static void deleteData() {
- deactivateUser(LOGIN);
+ public static void deleteAndRestoreData() {
+ userRule.deactivateUsers(LOGIN, "signuplogin");
addGroupPermission("anyone", "scan");
}
@After
public void resetProperties() throws Exception {
setServerProperty(ORCHESTRATOR, "sonar.forceAuthentication", null);
+ setServerProperty(ORCHESTRATOR, "sonar.allowUsersToSignUp", null);
}
@Test
String login = format("login-%s", userId);
String name = format("name-%s", userId);
String password = "!ascii-only:-)@";
- createUser(login, name, password);
+ userRule.createUser(login, name, password);
// authenticate
WsClient wsClient = new HttpWsClient(new HttpConnector.Builder().url(ORCHESTRATOR.getServer().getUrl()).credentials(login, password).build());
*/
@Test
public void basic_authentication_does_not_support_utf8_passwords() {
- String userId = UUID.randomUUID().toString();
- String login = format("login-%s", userId);
+ String login = LOGIN;
// see http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
String password = "κόσμε";
// create user with a UTF-8 password
- createUser(login, format("name-%s", userId), password);
+ userRule.createUser(login, LOGIN, password);
// authenticate
assertThat(checkAuthenticationThroughWebService(login, password)).isFalse();
}
+ @Test
+ public void allow_users_to_sign_up() throws IOException {
+ setServerProperty(ORCHESTRATOR, "sonar.allowUsersToSignUp", "true");
+
+ new SeleneseTest(
+ Selenese.builder().setHtmlTestsInClasspath("allow_users_to_sign_up",
+ "/user/LocalAuthenticationTest/allow_users_to_sign_up.html").build()).runOn(ORCHESTRATOR);
+
+ // This check is failing because signup doesn't refresh the users ES index !
+ // Will be fixed by SONAR-7308
+// userRule.verifyUserExists("signuplogin", "SignUpName", null);
+ }
+
+ @Test
+ public void authentication_through_ui() {
+ new SeleneseTest(Selenese.builder().setHtmlTestsInClasspath("authentication",
+ "/user/LocalAuthenticationTest/login_successful.html",
+ "/user/LocalAuthenticationTest/login_wrong_password.html",
+ // SONAR-2132
+ "/user/LocalAuthenticationTest/redirect_to_original_url_after_direct_login.html",
+ // SONAR-2009
+ "/user/LocalAuthenticationTest/redirect_to_original_url_after_indirect_login.html"
+ ).build()).runOn(ORCHESTRATOR);
+
+ setServerProperty(ORCHESTRATOR, "sonar.forceAuthentication", "true");
+
+ new SeleneseTest(Selenese.builder().setHtmlTestsInClasspath("force-authentication",
+ // SONAR-3473
+ "/user/LocalAuthenticationTest/force-authentication.html"
+ ).build()).runOn(ORCHESTRATOR);
+ }
+
@Test
public void authentication_with_web_service() {
assertThat(checkAuthenticationThroughWebService("admin", "admin")).isTrue();
return result.contains("{\"valid\":true}");
}
- private static void createUser(String login, String password) {
- adminWsClient.wsConnector().call(
- new PostRequest("api/users/create")
- .setParam("login", login)
- .setParam("name", login)
- .setParam("password", password));
- }
-
- private static void createUser(String login, String name, String password) {
- adminWsClient.wsConnector().call(
- new PostRequest("api/users/create")
- .setParam("login", login)
- .setParam("name", name)
- .setParam("password", password));
- }
-
private static void addUserPermission(String login, String permission) {
adminWsClient.permissions().addUser(new AddUserWsRequest()
.setLogin(login)
.setPermission(permission));
}
- private static void deactivateUser(String login) {
- adminWsClient.wsConnector().call(
- new PostRequest("api/users/deactivate")
- .setParam("login", login));
- }
-
private static void removeGroupPermission(String groupName, String permission) {
adminWsClient.permissions().removeGroup(new RemoveGroupWsRequest()
.setGroupName(groupName)
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.sonar.orchestrator.Orchestrator;
-import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import org.assertj.core.api.Assertions;
import org.junit.rules.ExternalResource;
import org.sonarqube.ws.client.GetRequest;
return new UserRule(requireNonNull(orchestrator, "Orchestrator instance can not be null"));
}
- @Override
- protected void before() throws Throwable {
- adminWsClient = newAdminWsClient(orchestrator);
+ private WsClient adminWsClient(){
+ if (adminWsClient == null) {
+ adminWsClient = newAdminWsClient(orchestrator);
+ }
+ return adminWsClient;
}
- public void verifyUserExists(String login, String name, String email) {
+ public void verifyUserExists(String login, String name, @Nullable String email) {
Optional<Users.User> user = getUserByLogin(login);
assertThat(user).as("User with login '%s' hasn't been found", login).isPresent();
Assertions.assertThat(user.get().getLogin()).isEqualTo(login);
assertThat(getUserByLogin(login)).as("Unexpected user with login '%s' has been found", login).isAbsent();
}
- public Optional<Users.User> getUserByLogin(String login) {
- return FluentIterable.from(getUsers().getUsers()).firstMatch(new MatchUserLogin(login));
+
+ public void createUser(String login, String name, String password) {
+ adminWsClient().wsConnector().call(
+ new PostRequest("api/users/create")
+ .setParam("login", login)
+ .setParam("name", name)
+ .setParam("password", password));
}
- public List<Users.User> getUsersByEmails(String... emails) {
- List<Users.User> foundUsers = new ArrayList<>();
- for (String email : emails) {
- Optional<Users.User> user = FluentIterable.from(getUsers().getUsers()).firstMatch(new MatchUserLogin(email));
- if (user.isPresent()) {
- foundUsers.add(user.get());
- }
- }
- return foundUsers;
+ public void createUser(String login, String password) {
+ createUser(login, login, password);
+ }
+
+ public Optional<Users.User> getUserByLogin(String login) {
+ return FluentIterable.from(getUsers().getUsers()).firstMatch(new MatchUserLogin(login));
}
public Users getUsers() {
- WsResponse response = adminWsClient.wsConnector().call(
+ WsResponse response = adminWsClient().wsConnector().call(
new GetRequest("api/users/search"));
Assertions.assertThat(response.code()).isEqualTo(200);
return Users.parse(response.content());
}
- private class MatchUserLogin implements Predicate<Users.User> {
- private final String login;
-
- private MatchUserLogin(String login) {
- this.login = login;
- }
-
- @Override
- public boolean apply(@Nonnull Users.User user) {
- String login = user.getLogin();
- return login != null && login.equals(this.login) && user.isActive();
- }
- }
-
public void deactivateUsers(List<Users.User> users) {
for (Users.User user : users) {
- adminWsClient.wsConnector().call(
+ adminWsClient().wsConnector().call(
new PostRequest("api/users/deactivate")
.setParam("login", user.getLogin()));
}
}
}
}
+
+ private class MatchUserLogin implements Predicate<Users.User> {
+ private final String login;
+
+ private MatchUserLogin(String login) {
+ this.login = login;
+ }
+
+ @Override
+ public boolean apply(@Nonnull Users.User user) {
+ String login = user.getLogin();
+ return login != null && login.equals(this.login) && user.isActive();
+ }
+ }
}
<thead>
<tr>
<td>open</td>
- <td>sessions/new</td>
+ <td>/sessions/new</td>
<td></td>
</tr>
<tr>
</tr>
<tr>
<td>type</td>
- <td>login</td>
+ <td>id=login</td>
<td>admin</td>
</tr>
<tr>
<td>type</td>
- <td>password</td>
+ <td>id=password</td>
<td>admin</td>
</tr>
<tr>
</tr>
<tr>
<td>type</td>
- <td>login</td>
+ <td>id=login</td>
<td>tester</td>
</tr>
<tr>
<td>type</td>
- <td>password</td>
+ <td>id=password</td>
<td>password</td>
</tr>
<tr>
</tr>
<tr>
<td>type</td>
- <td>login</td>
+ <td>id=login</td>
<td>tester</td>
</tr>
<tr>
<td>type</td>
- <td>password</td>
+ <td>id=password</td>
<td>123</td>
</tr>
<tr>
</tr>
<tr>
<td>type</td>
- <td>login</td>
+ <td>id=login</td>
<td>tester</td>
</tr>
<tr>
<td>type</td>
- <td>password</td>
+ <td>id=password</td>
<td>123</td>
</tr>
<tr>
<!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>external_user_details</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <title>external_user_details</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
- <thead>
- <tr>
- <td rowspan="1" colspan="3">external_user_details</td>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>open</td>
- <td>/system</td>
- <td></td>
- </tr>
- <tr>
- <td>type</td>
- <td>login</td>
- <td>admin</td>
- </tr>
- <tr>
- <td>type</td>
- <td>password</td>
- <td>admin</td>
- </tr>
- <tr>
- <td>clickAndWait</td>
- <td>commit</td>
- <td></td>
- </tr>
- <tr>
- <td>waitForText</td>
- <td>id=content</td>
- <td>*External User Authentication*FakeRealm*</td>
- </tr>
- </tbody>
+ <thead>
+ <tr>
+ <td rowspan="1" colspan="3">external_user_details</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>open</td>
+ <td>/system</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=login</td>
+ <td>admin</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=password</td>
+ <td>admin</td>
+ </tr>
+ <tr>
+ <td>clickAndWait</td>
+ <td>commit</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>id=content</td>
+ <td>*External User Authentication*FakeRealm*</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"/>
+ <title>allow_users_to_sign_up</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+ <tbody>
+ <tr>
+ <td>open</td>
+ <td>/sessions/new</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>content</td>
+ <td>*Log In to SonarQube*</td>
+ </tr>
+ <tr>
+ <td>assertText</td>
+ <td>bd</td>
+ <td>*Not a member*</td>
+ </tr>
+ <tr>
+ <td>clickAndWait</td>
+ <td>link=Sign up</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=user_login</td>
+ <td>signuplogin</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=user_name</td>
+ <td>SignUpName</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=user_password</td>
+ <td>password</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=user_password_confirmation</td>
+ <td>password</td>
+ </tr>
+ <tr>
+ <td>clickAndWait</td>
+ <td>name=commit</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>assertText</td>
+ <td>infomsg</td>
+ <td>*Please log in*</td>
+ </tr>
+ <tr>
+ <td>open</td>
+ <td>/sessions/new</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>content</td>
+ <td>*Log In to SonarQube*</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=login</td>
+ <td>signuplogin</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=password</td>
+ <td>password</td>
+ </tr>
+ <tr>
+ <td>clickAndWait</td>
+ <td>name=commit</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>css=.navbar</td>
+ <td>*SignUpName*</td>
+ </tr>
+ <tr>
+ <td>click</td>
+ <td>Link=SignUpName</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>css=.navbar</td>
+ <td>*Log out*</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"/>
+ <title>force-authentication</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+ <thead>
+ <tr>
+ <td rowspan="1" colspan="3">force-authentication</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>open</td>
+ <td>/sessions/logout</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>open</td>
+ <td>/</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>assertLocation</td>
+ <td>*/sessions/new</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>content</td>
+ <td>*Log In to SonarQube*</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=login</td>
+ <td>admin</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=password</td>
+ <td>admin</td>
+ </tr>
+ <tr>
+ <td>clickAndWait</td>
+ <td>name=commit</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>css=.navbar</td>
+ <td>*Administrator*</td>
+ </tr>
+ <tr>
+ <td>open</td>
+ <td>/sessions/logout</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>assertLocation</td>
+ <td>*/sessions/new</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"/>
+ <title>login_successful</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+ <thead>
+ <tr>
+ <td rowspan="1" colspan="3">login_successful</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>open</td>
+ <td>/sessions/new</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>content</td>
+ <td>*Log In to SonarQube*</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=login</td>
+ <td>admin</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=password</td>
+ <td>admin</td>
+ </tr>
+ <tr>
+ <td>clickAndWait</td>
+ <td>commit</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>css=.navbar</td>
+ <td>*Administrator*</td>
+ </tr>
+ <tr>
+ <td>click</td>
+ <td>Link=Administrator</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>assertTextPresent</td>
+ <td>Log out</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>clickAndWait</td>
+ <td>link=Log out</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForElementPresent</td>
+ <td>link=Log in</td>
+ <td>Log in</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"/>
+ <title>login_wrong_password</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+ <tbody>
+ <tr>
+ <td>open</td>
+ <td>/sessions/new</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>content</td>
+ <td>*Log In to SonarQube*</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=login</td>
+ <td>admin</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=password</td>
+ <td>wrong</td>
+ </tr>
+ <tr>
+ <td>clickAndWait</td>
+ <td>commit</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>assertTextPresent</td>
+ <td>Authentication failed</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"/>
+ <title>redirect-to-original-url-after-direct-login</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+ <tbody>
+ <tr>
+ <td>open</td>
+ <td>/sessions/logout</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>open</td>
+ <td>/settings?category=general</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>content</td>
+ <td>*Log In to SonarQube*</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=login</td>
+ <td>admin</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=password</td>
+ <td>admin</td>
+ </tr>
+ <tr>
+ <td>clickAndWait</td>
+ <td>name=commit</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>css=.navbar</td>
+ <td>*Administrator*</td>
+ </tr>
+ <tr>
+ <td>assertLocation</td>
+ <td>glob:*/settings?category=general*</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"/>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+ <tbody>
+ <tr>
+ <td>open</td>
+ <td>/sessions/logout</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>open</td>
+ <td>/settings/index</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>assertLocation</td>
+ <td>*/sessions/new</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>content</td>
+ <td>*Log In to SonarQube*</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=login</td>
+ <td>admin</td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>id=password</td>
+ <td>admin</td>
+ </tr>
+ <tr>
+ <td>clickAndWait</td>
+ <td>commit</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>waitForText</td>
+ <td>css=.navbar</td>
+ <td>*Administrator*</td>
+ </tr>
+ <tr>
+ <td>assertLocation</td>
+ <td>*/settings/index</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>assertElementPresent</td>
+ <td>plugins</td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+</body>
+</html>
</tr>
<tr>
<td>type</td>
- <td>login</td>
+ <td>id=login</td>
<td>account-user</td>
</tr>
<tr>
<td>type</td>
- <td>password</td>
+ <td>id=password</td>
<td>password</td>
</tr>
<tr>
</tr>
<tr>
<td>type</td>
- <td>login</td>
+ <td>id=login</td>
<td>account-user</td>
</tr>
<tr>
<td>type</td>
- <td>password</td>
+ <td>id=password</td>
<td>new_password</td>
</tr>
<tr>
</tr>
<tr>
<td>type</td>
- <td>login</td>
+ <td>id=login</td>
<td>account-user</td>
</tr>
<tr>
<td>type</td>
- <td>password</td>
+ <td>id=password</td>
<td>password</td>
</tr>
<tr>
</tr>
<tr>
<td>type</td>
- <td>login</td>
+ <td>id=login</td>
<td>account-user</td>
</tr>
<tr>
<td>type</td>
- <td>password</td>
+ <td>id=password</td>
<td>password</td>
</tr>
<tr>