diff --git a/resources/assets/scripts/components/auth/LoginForm.vue b/resources/assets/scripts/components/auth/LoginForm.vue
index 07236d550..067fb9290 100644
--- a/resources/assets/scripts/components/auth/LoginForm.vue
+++ b/resources/assets/scripts/components/auth/LoginForm.vue
@@ -5,29 +5,30 @@
>
-
-
{{ $t('auth.forgot_password.label') }}
diff --git a/tests/Browser/BrowserTestCase.php b/tests/Browser/BrowserTestCase.php
index 3e7d08c01..dd96930a8 100644
--- a/tests/Browser/BrowserTestCase.php
+++ b/tests/Browser/BrowserTestCase.php
@@ -41,6 +41,7 @@ abstract class BrowserTestCase extends TestCase
{
$options = (new ChromeOptions)->addArguments([
'--disable-gpu',
+ '--disable-infobars',
]);
return RemoteWebDriver::create(
diff --git a/tests/Browser/Pages/BasePage.php b/tests/Browser/Pages/BasePage.php
new file mode 100644
index 000000000..7d8efb513
--- /dev/null
+++ b/tests/Browser/Pages/BasePage.php
@@ -0,0 +1,16 @@
+ '#grid-username',
+ '@password' => '#grid-password',
+ '@loginButton' => '#grid-login-button',
+ '@forgotPassword' => 'a[aria-label="Forgot password"]',
+ ];
+ }
+}
diff --git a/tests/Browser/Processes/Authentication/LoginProcessTest.php b/tests/Browser/Processes/Authentication/LoginProcessTest.php
new file mode 100644
index 000000000..1e0f8a0be
--- /dev/null
+++ b/tests/Browser/Processes/Authentication/LoginProcessTest.php
@@ -0,0 +1,88 @@
+user = factory(User::class)->create([
+ 'email' => 'test@example.com',
+ 'password' => Hash::make('Password123'),
+ ]);
+ }
+
+ /**
+ * Test that a user can login successfully using their email address.
+ */
+ public function testLoginUsingEmail()
+ {
+ $this->browse(function (PterodactylBrowser $browser) {
+ $browser->visit(new LoginPage)
+ ->waitFor('@username')
+ ->type('@username', 'test@example.com')
+ ->type('@password', 'Password123')
+ ->click('@loginButton')
+ ->waitForReload()
+ ->assertPathIs('/')
+ ->assertAuthenticatedAs($this->user);
+ });
+ }
+
+ /**
+ * Test that a user can login successfully using their username.
+ */
+ public function testLoginUsingUsername()
+ {
+ $this->browse(function (PterodactylBrowser $browser) {
+ $browser->visit(new LoginPage)
+ ->waitFor('@username')
+ ->type('@username', $this->user->username)
+ ->type('@password', 'Password123')
+ ->click('@loginButton')
+ ->waitForReload()
+ ->assertPathIs('/')
+ ->assertAuthenticatedAs($this->user);
+ });
+ }
+
+ /**
+ * Test that entering the wrong password shows the expected error and then allows
+ * us to login without clearing the username field.
+ */
+ public function testLoginWithErrors()
+ {
+ $this->browse(function (PterodactylBrowser $browser) {
+ $browser->logout()
+ ->visit(new LoginPage())
+ ->waitFor('@username')
+ ->type('@username', 'test@example.com')
+ ->type('@password', 'invalid')
+ ->click('@loginButton')
+ ->waitFor('.alert.error')
+ ->assertSeeIn('.alert.error', trans('auth.failed'))
+ ->assertValue('@username', 'test@example.com')
+ ->assertValue('@password', '')
+ ->assertFocused('@password')
+ ->type('@password', 'Password123')
+ ->keys('@password', [WebDriverKeys::ENTER])
+ ->waitForReload()
+ ->assertPathIs('/')
+ ->assertAuthenticatedAs($this->user);
+ });
+ }
+}