From ce6cf6e4ac13916604436c6915bbe91a5da8a2f2 Mon Sep 17 00:00:00 2001 From: Tony Lea Date: Wed, 12 Jun 2024 17:30:04 -0400 Subject: [PATCH 1/4] Adding more dusk tests --- .../views/components/layouts/app.blade.php | 2 +- .../pages/auth/password/[token].blade.php | 12 ++- .../pages/auth/password/confirm.blade.php | 10 ++- .../views/pages/auth/password/reset.blade.php | 8 +- .../two-factor-authentication/index.blade.php | 2 +- routes/web.php | 11 +-- src/AuthServiceProvider.php | 10 +++ src/Providers/DuskServiceProvider.php | 25 +++++++ tests/Browser/ConfirmPasswordTest.php | 55 ++++++++++++++ tests/Browser/ForgotPasswordTest.php | 73 +++++++++++++++++++ tests/Browser/LoginTest.php | 3 +- tests/Browser/LogoutTest.php | 0 tests/Browser/Pages/ConfirmPassword.php | 16 ++++ tests/Browser/Pages/Login.php | 12 +-- tests/Browser/Pages/PasswordResetRequest.php | 16 ++++ tests/Browser/Pages/TwoFactorAuth.php | 16 ++++ tests/Browser/Pages/TwoFactorChallenge.php | 16 ++++ tests/Browser/TwoFactorAuthTest.php | 30 ++++++++ tests/Browser/TwoFactorChallengeTest.php | 29 ++++++++ 19 files changed, 309 insertions(+), 37 deletions(-) create mode 100644 tests/Browser/ConfirmPasswordTest.php create mode 100644 tests/Browser/ForgotPasswordTest.php create mode 100644 tests/Browser/LogoutTest.php create mode 100644 tests/Browser/Pages/ConfirmPassword.php create mode 100644 tests/Browser/Pages/PasswordResetRequest.php create mode 100644 tests/Browser/Pages/TwoFactorAuth.php create mode 100644 tests/Browser/Pages/TwoFactorChallenge.php create mode 100644 tests/Browser/TwoFactorAuthTest.php create mode 100644 tests/Browser/TwoFactorChallengeTest.php diff --git a/resources/views/components/layouts/app.blade.php b/resources/views/components/layouts/app.blade.php index a2dbce2..791b25b 100644 --- a/resources/views/components/layouts/app.blade.php +++ b/resources/views/components/layouts/app.blade.php @@ -26,7 +26,7 @@ @if(config('devdojo.auth.settings.enable_branding') && !app()->isLocal()) - +

Secured by DevDojo

diff --git a/resources/views/pages/auth/password/[token].blade.php b/resources/views/pages/auth/password/[token].blade.php index 5d50612..45e76ff 100644 --- a/resources/views/pages/auth/password/[token].blade.php +++ b/resources/views/pages/auth/password/[token].blade.php @@ -6,9 +6,7 @@ use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Password; use Illuminate\Auth\Events\PasswordReset; - -use function Laravel\Folio\name; - +use function Laravel\Folio\{middleware, name}; use Livewire\Volt\Component; use Livewire\Attributes\Validate; @@ -78,10 +76,10 @@ function ($user, $password) { />
- - - - Reset password + + + + Reset password @endvolt diff --git a/resources/views/pages/auth/password/confirm.blade.php b/resources/views/pages/auth/password/confirm.blade.php index 3e961ab..62c0b65 100644 --- a/resources/views/pages/auth/password/confirm.blade.php +++ b/resources/views/pages/auth/password/confirm.blade.php @@ -1,10 +1,14 @@ isLocal()){ + middleware('auth'); +} + name('password.confirm'); new class extends Component @@ -40,8 +44,8 @@ public function confirm() :show_subheadline="($language->passwordConfirm->show_subheadline ?? false)" />
- - Confirm password + + Confirm password @endvolt diff --git a/resources/views/pages/auth/password/reset.blade.php b/resources/views/pages/auth/password/reset.blade.php index 37647f3..33273ff 100644 --- a/resources/views/pages/auth/password/reset.blade.php +++ b/resources/views/pages/auth/password/reset.blade.php @@ -2,7 +2,7 @@ use Devdojo\Auth\Traits\HasConfigs; use Illuminate\Support\Facades\Password; -use function Laravel\Folio\name; +use function Laravel\Folio\{middleware, name}; use Livewire\Volt\Component; use Livewire\Attributes\Validate; @@ -68,13 +68,13 @@ public function sendResetPasswordLink() @else
- - Send password reset link + + Send password reset link @endif
Or - return to login + return to login
@endvolt diff --git a/resources/views/pages/user/two-factor-authentication/index.blade.php b/resources/views/pages/user/two-factor-authentication/index.blade.php index e5e0ddd..a95d08b 100644 --- a/resources/views/pages/user/two-factor-authentication/index.blade.php +++ b/resources/views/pages/user/two-factor-authentication/index.blade.php @@ -128,7 +128,7 @@ public function disable(){

Two factor authentication disabled.

When you enabled 2FA, you will be prompted for a secure code during authentication. This code can be retrieved from your phone's Google Authenticator application.

- Enable + Enable
@else diff --git a/routes/web.php b/routes/web.php index f77adf1..a383fc9 100644 --- a/routes/web.php +++ b/routes/web.php @@ -28,15 +28,6 @@ // Add social routes Route::get('auth/{driver}/redirect', [SocialController::class, 'redirect']); Route::get('auth/{driver}/callback', [SocialController::class, 'callback']); -}); - -Route::get('hey', function () { - $rowsArray = []; - $socialProviders = config('devdojo.auth.providers', []); - foreach ($socialProviders as $key => $provider) { - $provider['slug'] = $key; - array_push($rowsArray, $provider); - } - dd($rowsArray); }); + diff --git a/src/AuthServiceProvider.php b/src/AuthServiceProvider.php index fe8d988..fc74f24 100644 --- a/src/AuthServiceProvider.php +++ b/src/AuthServiceProvider.php @@ -80,6 +80,7 @@ public function boot(): void } $this->handleStarterKitFunctionality(); + $this->loadDynamicRoutesForTesting(); } private function registerAuthFolioDirectory(): void @@ -150,4 +151,13 @@ public function register() $this->app->register(\Devdojo\Auth\Providers\DuskServiceProvider::class); } } + + private function loadDynamicRoutesForTesting() + { + if (app()->environment('testing') || app()->environment('local')) { + Route::get('/auth/password_confirmation_test', function () { + return 'Test Confirmed'; + })->middleware('web', 'auth', 'password.confirm'); + } + } } diff --git a/src/Providers/DuskServiceProvider.php b/src/Providers/DuskServiceProvider.php index 367ab45..a27f63a 100644 --- a/src/Providers/DuskServiceProvider.php +++ b/src/Providers/DuskServiceProvider.php @@ -45,6 +45,18 @@ public function boot(): void return $this; }); + Browser::macro('loginAsJohnDoe', function(){ + $this->loginAs(\Devdojo\Auth\Models\User::where('email', 'johndoe@gmail.com')->first()); + return $this; + }); + + Browser::macro('enable2FAforJohnDoe', function(){ + $johnDoe = \Devdojo\Auth\Models\User::where('email', 'johndoe@gmail.com')->first(); + $johnDoe->two_factor_confirmed_at = now(); + $johnDoe->save(); + return $this; + }); + Browser::macro('assertRedirectAfterAuthUrlIsCorrect', function () { $redirectExpectedToBe = '/'; if (class_exists(\Devdojo\Genesis\Genesis::class)) { @@ -67,5 +79,18 @@ public function boot(): void return $this; }); + + Browser::macro('typeAndSubmit', function (?string $selector, string $value) { + $this->type($selector, $value) + ->click('@submit-button'); + + return $this; + }); + + Browser::macro('visitPasswordConfirmTestPage', function () { + $this->visit('/auth/password_confirmation_test'); + return $this; + }); + } } diff --git a/tests/Browser/ConfirmPasswordTest.php b/tests/Browser/ConfirmPasswordTest.php new file mode 100644 index 0000000..ac6aee3 --- /dev/null +++ b/tests/Browser/ConfirmPasswordTest.php @@ -0,0 +1,55 @@ +browse(function (Browser $browser) { + $browser + ->visit(new ConfirmPassword) + ->assertPathIs('/auth/login'); + }); +}); + +test('Password Confirm Protected Page Redirects', function () { + $browser = $this->browse(function (Browser $browser) { + $browser + ->visitPasswordConfirmTestPage() + ->assertPathIs('/auth/login') + ->createJohnDoe() + ->loginAsJohnDoe() + ->visitPasswordConfirmTestPage() + ->assertPathIs('/auth/password/confirm'); + }); +}); + +test('Password Confirm Works', function(){ + $browser = $this->browse(function (Browser $browser) { + $browser + ->createJohnDoe() + ->loginAsJohnDoe() + ->visit(new ConfirmPassword) + ->type('@password-input', 'password') + ->clickAndWaitForReload('@submit-button') + ->assertRedirectAfterAuthUrlIsCorrect(); + }); +}); + +test('Password Confirm Works and redirect to password protected page', function(){ + $browser = $this->browse(function (Browser $browser) { + $browser + ->createJohnDoe() + ->loginAsJohnDoe() + ->visitPasswordConfirmTestPage() + ->type('@password-input', 'password') + ->clickAndWaitForReload('@submit-button') + ->assertSee('Test Confirmed'); + }); +}); \ No newline at end of file diff --git a/tests/Browser/ForgotPasswordTest.php b/tests/Browser/ForgotPasswordTest.php new file mode 100644 index 0000000..67682bc --- /dev/null +++ b/tests/Browser/ForgotPasswordTest.php @@ -0,0 +1,73 @@ +browse(function (Browser $browser) { + $browser + ->visit(new PasswordResetRequest) + ->authAttributeRemove('#email', 'required') + ->testValidationErrorOnSubmit('The email field is required'); + }); +}); + +test('Invalid Email Validation', function () { + $browser = $this->browse(function (Browser $browser) { + $browser + ->visit(new PasswordResetRequest) + ->authAttributeChange('#email', 'type', 'text') + ->type('@email-input', 'johndoe') + ->testValidationErrorOnSubmit('The email field must be a valid email address'); + }); +}); + +test('Email Does Not Exist', function () { + $browser = $this->browse(function (Browser $browser) { + $browser + ->visit(new PasswordResetRequest) + ->type('@email-input', 'jimmycrackcorn@gmail.com') + ->testValidationErrorOnSubmit('We can\'t find a user with that email address'); + }); +}); + +test('Email reset functionality', function () { + $browser = $this->browse(function (Browser $browser) { + + $browser + ->visit(new PasswordResetRequest) + ->createJohnDoe() + ->clearLogFile() + ->typeAndSubmit('@email-input', 'johndoe@gmail.com') + ->waitForText('We have emailed your password reset link') + ->getLogFile(function ($content) use ($browser) { + + $foundLine = $this->findLineContainingSubstring($content, 'Reset Password:'); + $url = str_replace('Reset Password: ', '', $foundLine); + $browser + ->visit($url) + ->assertSeeIn('#auth-heading-title', 'Reset Password') + ->type('@password-input', 'password123') + ->type('@password-confirm-input', 'password123') + ->clickAndWaitForReload('@submit-button') + ->assertRedirectAfterAuthUrlIsCorrect(); + }); + }); +}); + +test('Link to Login Page', function () { + $browser = $this->browse(function (Browser $browser) { + $browser + ->visit(new PasswordResetRequest) + ->click('@login-link') + ->waitFor('@auth-login') + ->assertPathIs('/auth/login'); + }); +}); \ No newline at end of file diff --git a/tests/Browser/LoginTest.php b/tests/Browser/LoginTest.php index 0d2ac63..40f0dbf 100644 --- a/tests/Browser/LoginTest.php +++ b/tests/Browser/LoginTest.php @@ -10,7 +10,8 @@ $this->browse(function (Browser $browser) { $browser->visit(new Login) ->createJohnDoe() - ->loginAsJohnDoe(); + ->formLoginAsJohnDoe() + ->assertRedirectAfterAuthUrlIsCorrect(); }); }); diff --git a/tests/Browser/LogoutTest.php b/tests/Browser/LogoutTest.php new file mode 100644 index 0000000..e69de29 diff --git a/tests/Browser/Pages/ConfirmPassword.php b/tests/Browser/Pages/ConfirmPassword.php new file mode 100644 index 0000000..7b1a8e9 --- /dev/null +++ b/tests/Browser/Pages/ConfirmPassword.php @@ -0,0 +1,16 @@ +visit('/auth/login') @@ -23,17 +23,9 @@ public function loginAsJohnDoe(Browser $browser) ->click('@submit-button') ->waitFor('@password-input') ->type('@password-input', 'password') - ->clickAndWaitForReload('@submit-button') - ->assertRedirectAfterAuthUrlIsCorrect(); + ->clickAndWaitForReload('@submit-button'); return $this; } - public function typeAndSubmit(Browser $browser, $selector, $value) - { - $browser->type($selector, $value) - ->click('@submit-button'); - - return $this; - } } diff --git a/tests/Browser/Pages/PasswordResetRequest.php b/tests/Browser/Pages/PasswordResetRequest.php new file mode 100644 index 0000000..3aa986f --- /dev/null +++ b/tests/Browser/Pages/PasswordResetRequest.php @@ -0,0 +1,16 @@ +browse(function (Browser $browser) { + $browser->visit(new TwoFactorAuth) + ->assertPathIs('/auth/login'); + }); +}); + +test('Successfully View 2FA Setup Page', function () { + + $this->browse(function (Browser $browser) { + $browser + ->createJohnDoe() + ->loginAsJohnDoe() + ->visit(new TwoFactorAuth) + ->assertSee('Two factor authentication disabled') + ->click('@enable-button') + ->waitForText('Finish enabling two factor authentication') + ->assertSee('Finish enabling two factor authentication'); + }); +}); + diff --git a/tests/Browser/TwoFactorChallengeTest.php b/tests/Browser/TwoFactorChallengeTest.php new file mode 100644 index 0000000..f2ead27 --- /dev/null +++ b/tests/Browser/TwoFactorChallengeTest.php @@ -0,0 +1,29 @@ +browse(function (Browser $browser) { + $browser->visit(new TwoFactorChallenge) + ->assertPathIs('/auth/login'); + }); +}); + +test('User logs in with 2fa enabled and redirected to challenge', function () { + // Turn on 2FA site-wide + $this->setConfig('devdojo.auth.settings.enable_2fa', true); + $this->browse(function (Browser $browser) { + $browser->visit(new Login) + ->createJohnDoe() + ->enable2FAforJohnDoe() + ->formLoginAsJohnDoe() + ->assertPathIs('/auth/two-factor-challenge'); + + $browser->pause(2000); + }); +}); \ No newline at end of file From 5091874bcffa5933cd63b9abcb99b8d2871851b2 Mon Sep 17 00:00:00 2001 From: tnylea Date: Wed, 12 Jun 2024 21:30:32 +0000 Subject: [PATCH 2/4] Fixes coding style --- routes/web.php | 1 - src/Providers/DuskServiceProvider.php | 7 +++++-- tests/Browser/ConfirmPasswordTest.php | 14 +++++++------- tests/Browser/ForgotPasswordTest.php | 2 +- tests/Browser/Pages/ConfirmPassword.php | 2 +- tests/Browser/Pages/Login.php | 1 - tests/Browser/Pages/PasswordResetRequest.php | 2 +- tests/Browser/Pages/TwoFactorAuth.php | 2 +- tests/Browser/Pages/TwoFactorChallenge.php | 2 +- tests/Browser/TwoFactorAuthTest.php | 1 - tests/Browser/TwoFactorChallengeTest.php | 4 ++-- 11 files changed, 19 insertions(+), 19 deletions(-) diff --git a/routes/web.php b/routes/web.php index a383fc9..6ed2435 100644 --- a/routes/web.php +++ b/routes/web.php @@ -30,4 +30,3 @@ Route::get('auth/{driver}/callback', [SocialController::class, 'callback']); }); - diff --git a/src/Providers/DuskServiceProvider.php b/src/Providers/DuskServiceProvider.php index a27f63a..9e810c4 100644 --- a/src/Providers/DuskServiceProvider.php +++ b/src/Providers/DuskServiceProvider.php @@ -45,15 +45,17 @@ public function boot(): void return $this; }); - Browser::macro('loginAsJohnDoe', function(){ + Browser::macro('loginAsJohnDoe', function () { $this->loginAs(\Devdojo\Auth\Models\User::where('email', 'johndoe@gmail.com')->first()); + return $this; }); - Browser::macro('enable2FAforJohnDoe', function(){ + Browser::macro('enable2FAforJohnDoe', function () { $johnDoe = \Devdojo\Auth\Models\User::where('email', 'johndoe@gmail.com')->first(); $johnDoe->two_factor_confirmed_at = now(); $johnDoe->save(); + return $this; }); @@ -89,6 +91,7 @@ public function boot(): void Browser::macro('visitPasswordConfirmTestPage', function () { $this->visit('/auth/password_confirmation_test'); + return $this; }); diff --git a/tests/Browser/ConfirmPasswordTest.php b/tests/Browser/ConfirmPasswordTest.php index ac6aee3..a3fdfa6 100644 --- a/tests/Browser/ConfirmPasswordTest.php +++ b/tests/Browser/ConfirmPasswordTest.php @@ -10,7 +10,7 @@ uses(DatabaseMigrations::class); -test('Guest redirect to login page', function(){ +test('Guest redirect to login page', function () { $browser = $this->browse(function (Browser $browser) { $browser ->visit(new ConfirmPassword) @@ -23,17 +23,17 @@ $browser ->visitPasswordConfirmTestPage() ->assertPathIs('/auth/login') - ->createJohnDoe() + ->createJohnDoe() ->loginAsJohnDoe() ->visitPasswordConfirmTestPage() ->assertPathIs('/auth/password/confirm'); }); }); -test('Password Confirm Works', function(){ +test('Password Confirm Works', function () { $browser = $this->browse(function (Browser $browser) { $browser - ->createJohnDoe() + ->createJohnDoe() ->loginAsJohnDoe() ->visit(new ConfirmPassword) ->type('@password-input', 'password') @@ -42,14 +42,14 @@ }); }); -test('Password Confirm Works and redirect to password protected page', function(){ +test('Password Confirm Works and redirect to password protected page', function () { $browser = $this->browse(function (Browser $browser) { $browser - ->createJohnDoe() + ->createJohnDoe() ->loginAsJohnDoe() ->visitPasswordConfirmTestPage() ->type('@password-input', 'password') ->clickAndWaitForReload('@submit-button') ->assertSee('Test Confirmed'); }); -}); \ No newline at end of file +}); diff --git a/tests/Browser/ForgotPasswordTest.php b/tests/Browser/ForgotPasswordTest.php index 67682bc..b977a4f 100644 --- a/tests/Browser/ForgotPasswordTest.php +++ b/tests/Browser/ForgotPasswordTest.php @@ -70,4 +70,4 @@ ->waitFor('@auth-login') ->assertPathIs('/auth/login'); }); -}); \ No newline at end of file +}); diff --git a/tests/Browser/Pages/ConfirmPassword.php b/tests/Browser/Pages/ConfirmPassword.php index 7b1a8e9..2a85bd1 100644 --- a/tests/Browser/Pages/ConfirmPassword.php +++ b/tests/Browser/Pages/ConfirmPassword.php @@ -13,4 +13,4 @@ public function url(): string { return '/auth/password/confirm'; } -} \ No newline at end of file +} diff --git a/tests/Browser/Pages/Login.php b/tests/Browser/Pages/Login.php index 49d6ee4..ab9ddff 100644 --- a/tests/Browser/Pages/Login.php +++ b/tests/Browser/Pages/Login.php @@ -27,5 +27,4 @@ public function formLoginAsJohnDoe(Browser $browser) return $this; } - } diff --git a/tests/Browser/Pages/PasswordResetRequest.php b/tests/Browser/Pages/PasswordResetRequest.php index 3aa986f..3834074 100644 --- a/tests/Browser/Pages/PasswordResetRequest.php +++ b/tests/Browser/Pages/PasswordResetRequest.php @@ -13,4 +13,4 @@ public function url(): string { return '/auth/password/reset'; } -} \ No newline at end of file +} diff --git a/tests/Browser/Pages/TwoFactorAuth.php b/tests/Browser/Pages/TwoFactorAuth.php index 6546c38..5da8ef3 100644 --- a/tests/Browser/Pages/TwoFactorAuth.php +++ b/tests/Browser/Pages/TwoFactorAuth.php @@ -13,4 +13,4 @@ public function url(): string { return '/user/two-factor-authentication'; } -} \ No newline at end of file +} diff --git a/tests/Browser/Pages/TwoFactorChallenge.php b/tests/Browser/Pages/TwoFactorChallenge.php index 4840914..f778491 100644 --- a/tests/Browser/Pages/TwoFactorChallenge.php +++ b/tests/Browser/Pages/TwoFactorChallenge.php @@ -13,4 +13,4 @@ public function url(): string { return '/auth/two-factor-challenge'; } -} \ No newline at end of file +} diff --git a/tests/Browser/TwoFactorAuthTest.php b/tests/Browser/TwoFactorAuthTest.php index 24882c6..8b99dc0 100644 --- a/tests/Browser/TwoFactorAuthTest.php +++ b/tests/Browser/TwoFactorAuthTest.php @@ -27,4 +27,3 @@ ->assertSee('Finish enabling two factor authentication'); }); }); - diff --git a/tests/Browser/TwoFactorChallengeTest.php b/tests/Browser/TwoFactorChallengeTest.php index f2ead27..778ee7f 100644 --- a/tests/Browser/TwoFactorChallengeTest.php +++ b/tests/Browser/TwoFactorChallengeTest.php @@ -23,7 +23,7 @@ ->enable2FAforJohnDoe() ->formLoginAsJohnDoe() ->assertPathIs('/auth/two-factor-challenge'); - + $browser->pause(2000); }); -}); \ No newline at end of file +}); From 0b24759d4886c1caedacdc0966d908214d8bcabe Mon Sep 17 00:00:00 2001 From: Tony Lea Date: Wed, 12 Jun 2024 17:36:12 -0400 Subject: [PATCH 3/4] Adding update to URLs --- tests/Datasets/Urls.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Datasets/Urls.php b/tests/Datasets/Urls.php index bda05c7..9673208 100644 --- a/tests/Datasets/Urls.php +++ b/tests/Datasets/Urls.php @@ -5,6 +5,5 @@ '/auth/register', '/auth/verify', '/auth/password/reset', - '/auth/password/confirm', '/auth/password/SomeReallyLongtoken', ]); From 13ebc3fb0780ecc9a78909c00f1f9120c1cc65e3 Mon Sep 17 00:00:00 2001 From: Tony Lea Date: Wed, 12 Jun 2024 18:04:52 -0400 Subject: [PATCH 4/4] Getting all tests to pass --- tests/Browser/TwoFactorAuthTest.php | 3 ++- tests/Browser/TwoFactorChallengeTest.php | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Browser/TwoFactorAuthTest.php b/tests/Browser/TwoFactorAuthTest.php index 8b99dc0..bd61e69 100644 --- a/tests/Browser/TwoFactorAuthTest.php +++ b/tests/Browser/TwoFactorAuthTest.php @@ -15,7 +15,7 @@ }); test('Successfully View 2FA Setup Page', function () { - + $this->setConfig('devdojo.auth.settings.enable_2fa', true); $this->browse(function (Browser $browser) { $browser ->createJohnDoe() @@ -26,4 +26,5 @@ ->waitForText('Finish enabling two factor authentication') ->assertSee('Finish enabling two factor authentication'); }); + $this->resetConfig(); }); diff --git a/tests/Browser/TwoFactorChallengeTest.php b/tests/Browser/TwoFactorChallengeTest.php index 778ee7f..7ad9359 100644 --- a/tests/Browser/TwoFactorChallengeTest.php +++ b/tests/Browser/TwoFactorChallengeTest.php @@ -23,7 +23,6 @@ ->enable2FAforJohnDoe() ->formLoginAsJohnDoe() ->assertPathIs('/auth/two-factor-challenge'); - - $browser->pause(2000); }); + $this->resetConfig(); });