diff --git a/resources/assets/scripts/components/auth/ForgotPassword.vue b/resources/assets/scripts/components/auth/ForgotPassword.vue
index e06fa40b4..c224fd778 100644
--- a/resources/assets/scripts/components/auth/ForgotPassword.vue
+++ b/resources/assets/scripts/components/auth/ForgotPassword.vue
@@ -5,13 +5,14 @@
>
@@ -25,6 +26,7 @@
{{ $t('auth.go_to_login') }}
diff --git a/tests/Browser/Pages/LoginPage.php b/tests/Browser/Pages/LoginPage.php
index 06ec27b57..5fd42cbf6 100644
--- a/tests/Browser/Pages/LoginPage.php
+++ b/tests/Browser/Pages/LoginPage.php
@@ -15,10 +15,15 @@ class LoginPage extends BasePage
public function elements()
{
return [
+ '@email' => '#grid-email',
'@username' => '#grid-username',
'@password' => '#grid-password',
'@loginButton' => '#grid-login-button',
- '@forgotPassword' => 'a[aria-label="Forgot password"]',
+ '@submitButton' => 'button.btn.btn-jumbo[type="submit"]',
+ '@forgotPassword' => 'a[href="/auth/password"][aria-label="Forgot password"]',
+ '@goToLogin' => 'a[href="/auth/login"][aria-label="Go to login"]',
+ '@alertSuccess' => 'div[role="alert"].success > span.message',
+ '@alertDanger' => 'div[role="alert"].danger > span.message',
];
}
}
diff --git a/tests/Browser/Processes/Authentication/ForgotPasswordProcessTest.php b/tests/Browser/Processes/Authentication/ForgotPasswordProcessTest.php
new file mode 100644
index 000000000..ab8c9bc8a
--- /dev/null
+++ b/tests/Browser/Processes/Authentication/ForgotPasswordProcessTest.php
@@ -0,0 +1,50 @@
+browse(function (PterodactylBrowser $browser) {
+ $browser->visit(new LoginPage)
+ ->assertSee(trans('auth.forgot_password.label'))
+ ->click('@forgotPassword')
+ ->waitForLocation('/auth/password')
+ ->assertFocused('@email')
+ ->assertSeeIn('.input-open > p.text-xs', trans('auth.forgot_password.label_help'))
+ ->assertSeeIn('@submitButton', trans('auth.forgot_password.button'))
+ ->type('@email', 'unassociated@example.com')
+ ->assertSeeIn('@goToLogin', trans('auth.go_to_login'))
+ ->press('@submitButton')
+ ->waitForLocation('/auth/login')
+ ->assertSeeIn('div[role="alert"].success > span.message', 'We have e-mailed your password reset link!')
+ ->assertFocused('@username')
+ ->assertValue('@username', 'unassociated@example.com');
+ });
+ }
+
+ /**
+ * Test that you can type in your email address and then click forgot password and have
+ * the email maintained on the new page.
+ */
+ public function testEmailCarryover()
+ {
+ $this->browse(function (PterodactylBrowser $browser) {
+ $browser->visit(new LoginPage)
+ ->type('@username', 'dane@example.com')
+ ->click('@forgotPassword')
+ ->waitForLocation('/auth/password')
+ ->assertFocused('@email')
+ ->assertValue('@email', 'dane@example.com');
+ });
+ }
+}
diff --git a/tests/Browser/PterodactylBrowser.php b/tests/Browser/PterodactylBrowser.php
index ba08a0707..57a790844 100644
--- a/tests/Browser/PterodactylBrowser.php
+++ b/tests/Browser/PterodactylBrowser.php
@@ -3,7 +3,39 @@
namespace Pterodactyl\Tests\Browser;
use Laravel\Dusk\Browser;
+use Illuminate\Support\Str;
+use PHPUnit\Framework\Assert as PHPUnit;
class PterodactylBrowser extends Browser
{
+ /**
+ * Perform a case insensitive search for a string in the body.
+ *
+ * @param string $text
+ * @return \Pterodactyl\Tests\Browser\PterodactylBrowser
+ */
+ public function assertSee($text)
+ {
+ return $this->assertSeeIn('', $text);
+ }
+
+ /**
+ * Perform a case insensitive search for a string in a given selector.
+ *
+ * @param string $selector
+ * @param string $text
+ * @return \Pterodactyl\Tests\Browser\PterodactylBrowser
+ */
+ public function assertSeeIn($selector, $text)
+ {
+ $fullSelector = $this->resolver->format($selector);
+ $element = $this->resolver->findOrFail($selector);
+
+ PHPUnit::assertTrue(
+ Str::contains(mb_strtolower($element->getText()), mb_strtolower($text)),
+ "Did not see expected text [{$text}] within element [{$fullSelector}] using case-insensitive search."
+ );
+
+ return $this;
+ }
}