diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..0cbe762
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,22 @@
+name: Test
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+
+jobs:
+ package-tests:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: shivammathur/setup-php@15c43e89cdef867065b0213be354c2841860869e
+ with:
+ php-version: '8.1'
+ - uses: actions/checkout@v3
+ - name: Install Dependencies
+ run: composer update && composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist && composer dump-autoload
+ - name: Execute tests (Unit and Feature tests) via PEST
+ run: vendor/bin/pest
diff --git a/.gitignore b/.gitignore
index fbc2c3f..aacfb3f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
composer.lock
node_modules/
vendor/
+composer.lock
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 17dcb14..d972dd0 100644
--- a/composer.json
+++ b/composer.json
@@ -25,14 +25,16 @@
"require-dev": {
"fakerphp/faker": "^1.9.1",
"laravel/pint": "^1.0",
- "mockery/mockery": "^1.4.4",
- "nunomaduro/collision": "^6.4",
- "pestphp/pest": "^1.22",
- "pestphp/pest-plugin-laravel": "^1.4",
- "spatie/laravel-ignition": "^1.0",
- "phpunit/phpunit": "^9.6",
- "pestphp/pest-plugin-mock": "^1.0",
- "orchestra/testbench": "^7.22"
+ "mockery/mockery": "^1.5",
+ "nunomaduro/collision": "^7.0",
+ "pestphp/pest": "^2.0",
+ "pestphp/pest-plugin-laravel": "^2.0",
+ "spatie/laravel-ignition": "^2.0",
+ "phpunit/phpunit": "^10.0",
+ "pestphp/pest-plugin-mock": "^2.0",
+ "orchestra/testbench": "^8.0",
+ "spatie/laravel-ray": "^1.32",
+ "nunomaduro/larastan": "^2.0"
},
"autoload": {
"psr-4": {
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..b11c7eb
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,18 @@
+includes:
+ - ./vendor/nunomaduro/larastan/extension.neon
+
+parameters:
+
+ paths:
+ - src/
+
+ # Level 9 is the highest level
+ level: 5
+
+# ignoreErrors:
+# - '#PHPDoc tag @var#'
+#
+# excludePaths:
+# - ./*/*/FileToBeExcluded.php
+#
+# checkMissingIterableValueType: false
\ No newline at end of file
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..fb5ed85
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ ./tests
+
+
+
+
+
+
+
+
+
diff --git a/phpunit.xml.bak b/phpunit.xml.bak
new file mode 100644
index 0000000..ae550e1
--- /dev/null
+++ b/phpunit.xml.bak
@@ -0,0 +1,22 @@
+
+
+
+
+ ./tests
+
+
+
+
+ ./functions
+ ./src
+
+
+
+
+
+
+
diff --git a/src/Authenticator.php b/src/Authenticator.php
index 5f2e5a3..4b2b072 100644
--- a/src/Authenticator.php
+++ b/src/Authenticator.php
@@ -64,9 +64,11 @@ class Authenticator
*
* @param string $name The name of the auth
*/
- public function __construct(private readonly string $name)
+ public function __construct(private readonly string $name, Collection $parameters = null)
{
- $this->parameters = Collection::make([
+ $parameters = $parameters ?? new Collection();
+
+ $this->parameters = $parameters->merge([
'enabled' => true,
'registration_enabled' => true,
'forgot_password_enabled' => true,
diff --git a/src/Registrators/Registrator.php b/src/Builder.php
similarity index 67%
rename from src/Registrators/Registrator.php
rename to src/Builder.php
index 5fec40c..5fdee3b 100644
--- a/src/Registrators/Registrator.php
+++ b/src/Builder.php
@@ -1,10 +1,13 @@
registrators)
- ->map(function ($registrator, $category) use ($authenticator, $name) {
- return new $registrator($authenticator, $category);
- })->map(function (RegistratorInterface $registrator) {
- $registrator->boot();
+ ->map(function ($registrator) use ($authenticator) {
+
+ /**
+ * Build the registrator.
+ *
+ * @var AbstractRegistrator $registrator
+ */
+ $registrator = $this->app->make($registrator);
+ $registrator->withAuthName($authenticator->name());
+
+ /**
+ * Merge all parameters from the registrator into the authenticator
+ */
+ $authenticator->merge(
+ $registrator->collectAndMergeParameters()
+ );
+
+ return $registrator;
+ })->map(function (AbstractRegistrator $registrator) use ($authenticator) {
+
+ /**
+ * Boot the registrator
+ */
+ $registrator->boot($authenticator->parameters);
});
/**
diff --git a/src/Contracts/AbstractRegistrator.php b/src/Contracts/AbstractRegistrator.php
new file mode 100644
index 0000000..bda1b09
--- /dev/null
+++ b/src/Contracts/AbstractRegistrator.php
@@ -0,0 +1,52 @@
+authName = $authName;
+
+ return $this;
+ }
+
+ /**
+ * This function will collect and merge all parameters inside the provided Authenticator
+ * @see Authenticator::merge()
+ */
+ public abstract function collectAndMergeParameters(): Collection;
+
+ /**
+ * Set of actions to be performed when booting the auth.
+ * @param Collection $allParameters All the parameters gathered by the authentication system
+ */
+ public abstract function boot(Collection $allParameters): void;
+}
diff --git a/src/Contracts/RegistratorInterface.php b/src/Contracts/RegistratorInterface.php
deleted file mode 100644
index 19b6b07..0000000
--- a/src/Contracts/RegistratorInterface.php
+++ /dev/null
@@ -1,25 +0,0 @@
- $this->faker->name,
+ 'email' => $this->faker->unique()->safeEmail,
+ 'email_verified_at' => now(),
+ 'password' => bcrypt('password'),
+ ];
+ }
+}
\ No newline at end of file
diff --git a/src/Http/Middleware/InjectIntoApplication.php b/src/Http/Middleware/InjectIntoApplication.php
index 457b367..4cf49a3 100644
--- a/src/Http/Middleware/InjectIntoApplication.php
+++ b/src/Http/Middleware/InjectIntoApplication.php
@@ -3,8 +3,8 @@
namespace Illegal\InsideAuth\Http\Middleware;
use Closure;
+use Illegal\InsideAuth\Builder;
use Illegal\InsideAuth\InsideAuth;
-use Illegal\InsideAuth\Registrators\Registrator;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -12,7 +12,7 @@
* This class will inject the current authenticator into:
* - The request
* - The current property of the Registrator / InsideAuth facade
- * @see Registrator::current()
+ * @see Builder::current()
* @see InsideAuth::current()
*/
class InjectIntoApplication
diff --git a/src/InsideAuth.php b/src/InsideAuth.php
index 9b0b651..ec209d3 100644
--- a/src/InsideAuth.php
+++ b/src/InsideAuth.php
@@ -2,16 +2,15 @@
namespace Illegal\InsideAuth;
-use Illegal\InsideAuth\Registrators\Registrator;
use Illuminate\Support\Facades\Facade;
/**
- * @mixin Registrator
+ * @mixin Builder
*/
class InsideAuth extends Facade
{
public static function getFacadeAccessor(): string
{
- return Registrator::class;
+ return Builder::class;
}
}
diff --git a/src/Models/User.php b/src/Models/User.php
index 256ada7..8f7a644 100644
--- a/src/Models/User.php
+++ b/src/Models/User.php
@@ -3,6 +3,7 @@
namespace Illegal\InsideAuth\Models;
use Illegal\InsideAuth\Events\UserDeleted;
+use Illegal\InsideAuth\Factories\UserFactory;
use Illegal\InsideAuth\InsideAuth;
use Illegal\LaravelUtils\Contracts\HasPrefix;
use Illuminate\Auth\Notifications\ResetPassword as ResetPasswordNotification;
@@ -125,4 +126,12 @@ public function sendEmailVerificationNotification(): void
$this->notify($notification);
}
+
+ /**
+ * Create a new factory instance for the model.
+ */
+ protected static function newFactory(): UserFactory
+ {
+ return UserFactory::new();
+ }
}
diff --git a/src/Providers/ServiceProvider.php b/src/Providers/ServiceProvider.php
index d6a593d..ef78372 100644
--- a/src/Providers/ServiceProvider.php
+++ b/src/Providers/ServiceProvider.php
@@ -2,8 +2,11 @@
namespace Illegal\InsideAuth\Providers;
+use Illegal\InsideAuth\Builder;
use Illegal\InsideAuth\Passwords\PasswordBrokerManager;
-use Illegal\InsideAuth\Registrators\Registrator;
+use Illegal\InsideAuth\Registrators\MiddlewareRegistrator;
+use Illegal\InsideAuth\Registrators\RouteRegistrator;
+use Illegal\InsideAuth\Registrators\SecurityRegistrator;
use Illuminate\Foundation\Application;
use Illuminate\Support\ServiceProvider as IlluminateServiceProvider;
@@ -15,6 +18,7 @@ class ServiceProvider extends IlluminateServiceProvider
public function register(): void
{
$this->registerSingletons();
+ $this->bindServices();
}
/**
@@ -43,8 +47,26 @@ private function registerSingletons(): void
/**
* The Registrator class, used by the InsideAuth facade
*/
- $this->app->singleton(Registrator::class, function (Application $app) {
- return new Registrator();
+ $this->app->singleton(Builder::class, function (Application $app) {
+ return new Builder($app);
+ });
+ }
+
+ /**
+ * Bind the services to the DI
+ */
+ private function bindServices(): void
+ {
+ $this->app->bind(MiddlewareRegistrator::class, function(Application $app) {
+ return new MiddlewareRegistrator($app->make('config'), $app->make('router'));
+ });
+
+ $this->app->bind(RouteRegistrator::class, function(Application $app) {
+ return new RouteRegistrator($app->make('config'), $app->make('router'));
+ });
+
+ $this->app->bind(SecurityRegistrator::class, function(Application $app) {
+ return new SecurityRegistrator($app->make('config'), $app->make('router'), config('inside_auth.db.prefix'));
});
}
diff --git a/src/Registrators/MiddlewareRegistrator.php b/src/Registrators/MiddlewareRegistrator.php
index 08dd4c6..0b69f78 100644
--- a/src/Registrators/MiddlewareRegistrator.php
+++ b/src/Registrators/MiddlewareRegistrator.php
@@ -2,8 +2,7 @@
namespace Illegal\InsideAuth\Registrators;
-use Illegal\InsideAuth\Authenticator;
-use Illegal\InsideAuth\Contracts\RegistratorInterface;
+use Illegal\InsideAuth\Contracts\AbstractRegistrator;
use Illegal\InsideAuth\Http\Middleware\Authenticate;
use Illegal\InsideAuth\Http\Middleware\EnsureAuthIsEnabled;
use Illegal\InsideAuth\Http\Middleware\EnsureEmailIsVerified;
@@ -15,7 +14,6 @@
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\Support\Collection;
-use Illuminate\Support\Facades\Route;
use Illuminate\View\Middleware\ShareErrorsFromSession;
/**
@@ -29,51 +27,56 @@
* @property string $inject
* @property string $redirect_authenticated
*/
-class MiddlewareRegistrator implements RegistratorInterface
+class MiddlewareRegistrator extends AbstractRegistrator
{
/**
* The parameters collection, this will be merged inside the Authenticator, using the prefix
*/
private Collection $parameters;
+ /**
+ * @inheritdoc
+ */
+ protected string $prefix = 'middleware';
+
/**
* @inheritDoc
*/
- public function __construct(private readonly Authenticator $authenticator, string $prefix = 'middleware')
+ public function __get($key)
+ {
+ return $this->parameters->get($key);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function collectAndMergeParameters(): Collection
{
$this->parameters = collect([
- 'verified' => $this->authenticator->name() . '-verified',
- 'guest' => $this->authenticator->name() . '-guest',
- 'logged_in' => $this->authenticator->name() . '-logged',
- 'web' => $this->authenticator->name() . '-web',
- 'authenticated' => $this->authenticator->name() . '-authenticated',
- 'ensure_verified' => $this->authenticator->name() . '-ensure-email-is-verified',
- 'ensure_enabled' => $this->authenticator->name() . '-ensure-auth-is-enabled',
- 'inject' => $this->authenticator->name() . '-inject',
- 'redirect_authenticated' => $this->authenticator->name() . '-redirect-if-authenticated',
+ 'verified' => $this->authName . '-verified',
+ 'guest' => $this->authName . '-guest',
+ 'logged_in' => $this->authName . '-logged',
+ 'web' => $this->authName . '-web',
+ 'authenticated' => $this->authName . '-authenticated',
+ 'ensure_verified' => $this->authName . '-ensure-email-is-verified',
+ 'ensure_enabled' => $this->authName . '-ensure-auth-is-enabled',
+ 'inject' => $this->authName . '-inject',
+ 'redirect_authenticated' => $this->authName . '-redirect-if-authenticated',
]);
- $this->authenticator->merge($this->parameters->except([
+ return $this->parameters->except([
'authenticated',
'ensure_verified',
'ensure_enabled',
'inject',
'redirect_authenticated'
- ])->mapWithKeys(fn($value, $key) => [$prefix . '_' . $key => $value]));
- }
-
- /**
- * @inheritDoc
- */
- public function __get($key)
- {
- return $this->parameters->get($key);
+ ])->mapWithKeys(fn($value, $key) => [$this->prefix . '_' . $key => $value]);
}
/**
* @inheritDoc
*/
- public function boot(): void
+ public function boot(Collection $allParameters): void
{
/**
* Aliases for the base middlewares
@@ -82,16 +85,16 @@ public function boot(): void
* redirect_authenticated: Redirect the user if he is already authenticated
* inject: Inject the authenticator into the request
*/
- Route::aliasMiddleware($this->authenticated, Authenticate::class);
- Route::aliasMiddleware($this->ensure_verified, EnsureEmailIsVerified::class);
- Route::aliasMiddleware($this->ensure_enabled, EnsureAuthIsEnabled::class);
- Route::aliasMiddleware($this->redirect_authenticated, RedirectIfAuthenticated::class);
- Route::aliasMiddleware($this->inject, InjectIntoApplication::class);
+ $this->router->aliasMiddleware($this->authenticated, Authenticate::class);
+ $this->router->aliasMiddleware($this->ensure_verified, EnsureEmailIsVerified::class);
+ $this->router->aliasMiddleware($this->ensure_enabled, EnsureAuthIsEnabled::class);
+ $this->router->aliasMiddleware($this->redirect_authenticated, RedirectIfAuthenticated::class);
+ $this->router->aliasMiddleware($this->inject, InjectIntoApplication::class);
/**
* The web middleware, to be used on all web routes
*/
- Route::middlewareGroup($this->web, [
+ $this->router->middlewareGroup($this->web, [
EncryptCookies::class, // From Laravel
AddQueuedCookiesToResponse::class, // From Laravel
StartSession::class, // From Laravel
@@ -103,8 +106,8 @@ public function boot(): void
/**
* The guest middleware. Authenticated users will be redirected.
*/
- Route::middlewareGroup($this->guest, [
- $this->inject . ':' . $this->authenticator->name(),
+ $this->router->middlewareGroup($this->guest, [
+ $this->inject . ':' . $this->authName,
$this->ensure_enabled,
$this->redirect_authenticated
]);
@@ -113,17 +116,17 @@ public function boot(): void
* The logged in middleware, we just check that the user is logged in.
* It's not necessary that the user is also verified.
*/
- Route::middlewareGroup($this->logged_in, [
- $this->inject . ':' . $this->authenticator->name(),
+ $this->router->middlewareGroup($this->logged_in, [
+ $this->inject . ':' . $this->authName,
$this->ensure_enabled,
- $this->authenticated . ':' . $this->authenticator->route_login . ',' . $this->authenticator->security_guard
+ $this->authenticated . ':' . $allParameters->get('route_login') . ',' . $allParameters->get('security_guard')
]);
/**
* The main middleware group for the application.
* Checks that the user is logged in and that is verified.
*/
- Route::middlewareGroup($this->verified, [
+ $this->router->middlewareGroup($this->verified, [
$this->logged_in,
$this->ensure_verified
]);
diff --git a/src/Registrators/RouteRegistrator.php b/src/Registrators/RouteRegistrator.php
index 5d20b07..40eb8b1 100644
--- a/src/Registrators/RouteRegistrator.php
+++ b/src/Registrators/RouteRegistrator.php
@@ -2,8 +2,7 @@
namespace Illegal\InsideAuth\Registrators;
-use Illegal\InsideAuth\Authenticator;
-use Illegal\InsideAuth\Contracts\RegistratorInterface;
+use Illegal\InsideAuth\Contracts\AbstractRegistrator;
use Illegal\InsideAuth\Http\Controllers\AuthenticatedSessionController;
use Illegal\InsideAuth\Http\Controllers\ConfirmablePasswordController;
use Illegal\InsideAuth\Http\Controllers\EmailVerificationNotificationController;
@@ -19,7 +18,6 @@
use Illegal\InsideAuth\Http\Middleware\EnsureRegistrationIsEnabled;
use Illegal\InsideAuth\Http\Middleware\EnsureUserProfileIsEnabled;
use Illuminate\Support\Collection;
-use Illuminate\Support\Facades\Route;
/**
* @property string $login
@@ -38,57 +36,62 @@
* @property string $profile_update
* @property string $profile_destroy
*/
-class RouteRegistrator implements RegistratorInterface
+class RouteRegistrator extends AbstractRegistrator
{
/**
* The parameters collection, this will be merged inside the Authenticator, using the prefix
*/
private Collection $parameters;
+ /**
+ * @inheritdoc
+ */
+ protected string $prefix = 'route';
+
/**
* @inheritDoc
*/
- public function __construct(private readonly Authenticator $authenticator, string $prefix = 'route')
+ public function __get(string $key): string
{
- $this->parameters = collect([
- 'login' => $this->authenticator->name() . '.auth.login',
- 'register' => $this->authenticator->name() . '.auth.register',
- 'password_request' => $this->authenticator->name() . '.auth.password.request',
- 'password_email' => $this->authenticator->name() . '.auth.password.email',
- 'password_reset' => $this->authenticator->name() . '.auth.password.reset',
- 'password_store' => $this->authenticator->name() . '.auth.password.store',
- 'logout' => $this->authenticator->name() . '.auth.logout',
- 'verification_notice' => $this->authenticator->name() . '.auth.verification.notice',
- 'verification_verify' => $this->authenticator->name() . '.auth.verification.verify',
- 'verification_send' => $this->authenticator->name() . '.auth.verification.send',
- 'password_confirm' => $this->authenticator->name() . '.auth.password.confirm',
- 'password_update' => $this->authenticator->name() . '.auth.password.update',
- 'profile_edit' => $this->authenticator->name() . '.auth.profile.edit',
- 'profile_update' => $this->authenticator->name() . '.auth.profile.update',
- 'profile_destroy' => $this->authenticator->name() . '.auth.profile.destroy'
- ]);
-
- $this->authenticator->merge($this->parameters->mapWithKeys(fn($value, $key) => [$prefix . '_' . $key => $value]));
+ return $this->parameters->get($key);
}
/**
* @inheritDoc
*/
- public function __get(string $key): string
+ public function collectAndMergeParameters(): Collection
{
- return $this->parameters->get($key);
+ $this->parameters = collect([
+ 'login' => $this->authName . '.auth.login',
+ 'register' => $this->authName . '.auth.register',
+ 'password_request' => $this->authName . '.auth.password.request',
+ 'password_email' => $this->authName . '.auth.password.email',
+ 'password_reset' => $this->authName . '.auth.password.reset',
+ 'password_store' => $this->authName . '.auth.password.store',
+ 'logout' => $this->authName . '.auth.logout',
+ 'verification_notice' => $this->authName . '.auth.verification.notice',
+ 'verification_verify' => $this->authName . '.auth.verification.verify',
+ 'verification_send' => $this->authName . '.auth.verification.send',
+ 'password_confirm' => $this->authName . '.auth.password.confirm',
+ 'password_update' => $this->authName . '.auth.password.update',
+ 'profile_edit' => $this->authName . '.auth.profile.edit',
+ 'profile_update' => $this->authName . '.auth.profile.update',
+ 'profile_destroy' => $this->authName . '.auth.profile.destroy'
+ ]);
+
+ return $this->parameters->mapWithKeys(fn($value, $key) => [$this->prefix . '_' . $key => $value]);
}
/**
* @inheritDoc
*/
- public function boot(): void
+ public function boot(Collection $allParameters): void
{
- Route::prefix($this->authenticator->name())->middleware($this->authenticator->middleware_web)->group(function () {
+ $this->router->middleware($allParameters->get('middleware_web'))->prefix($this->authName)->group(function () use ($allParameters) {
/**
* Routes that are accessible to guests users
*/
- Route::middleware($this->authenticator->middleware_guest)->group(function () {
+ $this->router->middleware($allParameters->get('middleware_guest'))->group(function () {
$this->registerLoginRoutes();
$this->registerRegisterRoutes();
$this->registerForgotPasswordRoutes();
@@ -97,7 +100,7 @@ public function boot(): void
/**
* Routes that are accessible to logged in users, verified or not
*/
- Route::middleware($this->authenticator->middleware_logged_in)->group(function () {
+ $this->router->middleware($allParameters->get('middleware_logged_in'))->group(function () {
$this->registerLogoutRoutes();
$this->registerEmailVerificationRoutes();
});
@@ -105,7 +108,7 @@ public function boot(): void
/**
* Routes that are accessible to logged in and verified users
*/
- Route::middleware($this->authenticator->middleware_verified)->group(function () {
+ $this->router->middleware($allParameters->get('middleware_verified'))->group(function () {
$this->registerProfileRoutes();
});
});
@@ -116,8 +119,8 @@ public function boot(): void
*/
private function registerLoginRoutes(): void
{
- Route::get('login', [AuthenticatedSessionController::class, 'create'])->name($this->login);
- Route::post('login', [AuthenticatedSessionController::class, 'store']);
+ $this->router->get('login', [AuthenticatedSessionController::class, 'create'])->name($this->login);
+ $this->router->post('login', [AuthenticatedSessionController::class, 'store']);
}
/**
@@ -125,9 +128,9 @@ private function registerLoginRoutes(): void
*/
private function registerRegisterRoutes(): void
{
- Route::middleware(EnsureRegistrationIsEnabled::class)->group(function () {
- Route::get('register', [RegisteredUserController::class, 'create'])->name($this->register);
- Route::post('register', [RegisteredUserController::class, 'store']);
+ $this->router->middleware(EnsureRegistrationIsEnabled::class)->group(function () {
+ $this->router->get('register', [RegisteredUserController::class, 'create'])->name($this->register);
+ $this->router->post('register', [RegisteredUserController::class, 'store']);
});
}
@@ -136,12 +139,12 @@ private function registerRegisterRoutes(): void
*/
private function registerForgotPasswordRoutes(): void
{
- Route::middleware(EnsureForgotPasswordIsEnabled::class)->group(function () {
- Route::get('forgot-password', [PasswordResetLinkController::class, 'create'])->name($this->password_request);
- Route::post('forgot-password', [PasswordResetLinkController::class, 'store'])->name($this->password_email);
+ $this->router->middleware(EnsureForgotPasswordIsEnabled::class)->group(function () {
+ $this->router->get('forgot-password', [PasswordResetLinkController::class, 'create'])->name($this->password_request);
+ $this->router->post('forgot-password', [PasswordResetLinkController::class, 'store'])->name($this->password_email);
- Route::get('reset-password/{token}', [NewPasswordController::class, 'create'])->name($this->password_reset);
- Route::post('reset-password', [NewPasswordController::class, 'store'])->name($this->password_store);
+ $this->router->get('reset-password/{token}', [NewPasswordController::class, 'create'])->name($this->password_reset);
+ $this->router->post('reset-password', [NewPasswordController::class, 'store'])->name($this->password_store);
});
}
@@ -150,7 +153,7 @@ private function registerForgotPasswordRoutes(): void
*/
private function registerLogoutRoutes(): void
{
- Route::post('logout', [AuthenticatedSessionController::class, 'destroy'])->name($this->logout);
+ $this->router->post('logout', [AuthenticatedSessionController::class, 'destroy'])->name($this->logout);
}
/**
@@ -158,20 +161,20 @@ private function registerLogoutRoutes(): void
*/
public function registerEmailVerificationRoutes(): void
{
- Route::middleware(EnsureEmailVerificationIsEnabled::class)->group(function () {
- Route::get('verify-email', EmailVerificationPromptController::class)->name($this->verification_notice);
- Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
+ $this->router->middleware(EnsureEmailVerificationIsEnabled::class)->group(function () {
+ $this->router->get('verify-email', EmailVerificationPromptController::class)->name($this->verification_notice);
+ $this->router->get('verify-email/{id}/{hash}', VerifyEmailController::class)
->middleware(['signed', 'throttle:6,1'])
->name($this->verification_verify);
- Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
+ $this->router->post('email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
->middleware('throttle:6,1')
->name($this->verification_send);
- Route::get('confirm-password', [ConfirmablePasswordController::class, 'show'])->name($this->password_confirm);
- Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']);
+ $this->router->get('confirm-password', [ConfirmablePasswordController::class, 'show'])->name($this->password_confirm);
+ $this->router->post('confirm-password', [ConfirmablePasswordController::class, 'store']);
- Route::put('password', [PasswordController::class, 'update'])->name($this->password_update);
+ $this->router->put('password', [PasswordController::class, 'update'])->name($this->password_update);
});
}
@@ -180,10 +183,10 @@ public function registerEmailVerificationRoutes(): void
*/
public function registerProfileRoutes(): void
{
- Route::middleware(EnsureUserProfileIsEnabled::class)->group(function () {
- Route::get('/profile', [ProfileController::class, 'edit'])->name($this->profile_edit);
- Route::patch('/profile', [ProfileController::class, 'update'])->name($this->profile_update);
- Route::delete('/profile', [ProfileController::class, 'destroy'])->name($this->profile_destroy);
+ $this->router->middleware(EnsureUserProfileIsEnabled::class)->group(function () {
+ $this->router->get('/profile', [ProfileController::class, 'edit'])->name($this->profile_edit);
+ $this->router->patch('/profile', [ProfileController::class, 'update'])->name($this->profile_update);
+ $this->router->delete('/profile', [ProfileController::class, 'destroy'])->name($this->profile_destroy);
});
}
}
diff --git a/src/Registrators/SecurityRegistrator.php b/src/Registrators/SecurityRegistrator.php
index 5c996da..3a81ff1 100644
--- a/src/Registrators/SecurityRegistrator.php
+++ b/src/Registrators/SecurityRegistrator.php
@@ -2,18 +2,18 @@
namespace Illegal\InsideAuth\Registrators;
-use Illegal\InsideAuth\Authenticator;
-use Illegal\InsideAuth\Contracts\RegistratorInterface;
+use Illegal\InsideAuth\Contracts\AbstractRegistrator;
use Illegal\InsideAuth\Models\User;
+use Illuminate\Config\Repository;
+use Illuminate\Routing\Router;
use Illuminate\Support\Collection;
-use Illuminate\Support\Facades\Config;
/**
* @property string $guard
* @property string $provider
* @property string $password_broker
*/
-class SecurityRegistrator implements RegistratorInterface
+class SecurityRegistrator extends AbstractRegistrator
{
/**
* The parameters collection, this will be merged inside the Authenticator, using the prefix
@@ -21,17 +21,19 @@ class SecurityRegistrator implements RegistratorInterface
private Collection $parameters;
/**
- * @inheritDoc
+ * @inheritdoc
*/
- public function __construct(private readonly Authenticator $authenticator, string $prefix = 'security')
- {
- $this->parameters = collect([
- 'guard' => $this->authenticator->name(),
- 'provider' => $this->authenticator->name(),
- 'password_broker' => $this->authenticator->name(),
- ]);
+ protected string $prefix = 'security';
- $this->authenticator->merge($this->parameters->mapWithKeys(fn($value, $key) => [$prefix . '_' . $key => $value]));
+ /**
+ * The database prefix to use for the tables
+ */
+ protected string $dbPrefix;
+
+ public function __construct(Repository $config, Router $router, string $dbPrefix = "")
+ {
+ $this->dbPrefix = $dbPrefix;
+ parent::__construct($config, $router);
}
/**
@@ -45,12 +47,26 @@ public function __get($key)
/**
* @inheritDoc
*/
- public function boot(): void
+ public function collectAndMergeParameters(): Collection
+ {
+ $this->parameters = collect([
+ 'guard' => $this->authName,
+ 'provider' => $this->authName,
+ 'password_broker' => $this->authName,
+ ]);
+
+ return $this->parameters->mapWithKeys(fn($value, $key) => [$this->prefix . '_' . $key => $value]);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function boot(Collection $allParameters): void
{
/**
* Configure the guard
*/
- Config::set('auth.guards.' . $this->guard, [
+ $this->config->set('auth.guards.' . $this->guard, [
'driver' => 'session',
'provider' => $this->provider
]);
@@ -58,7 +74,7 @@ public function boot(): void
/**
* Configure the provider
*/
- Config::set('auth.providers.' . $this->provider, [
+ $this->config->set('auth.providers.' . $this->provider, [
'driver' => 'eloquent',
'model' => User::class
]);
@@ -66,9 +82,9 @@ public function boot(): void
/**
* Configure the password broker
*/
- Config::set('auth.passwords.' . $this->password_broker, [
+ $this->config->set('auth.passwords.' . $this->password_broker, [
'provider' => $this->provider,
- 'table' => config('inside_auth.db.prefix') . 'password_resets',
+ 'table' => $this->dbPrefix . 'password_resets',
'expire' => 60,
'throttle' => 60,
]);
diff --git a/tests/Feature/LoggedIn/AllEnabledTest.php b/tests/Feature/LoggedIn/AllEnabledTest.php
new file mode 100644
index 0000000..1ffb63c
--- /dev/null
+++ b/tests/Feature/LoggedIn/AllEnabledTest.php
@@ -0,0 +1,52 @@
+bootAuth();
+ $this->auth()->withDashboard('dashboard');
+ }
+);
+
+/**
+ * All routes are available
+ */
+it('routes to dashboard', fn() => $this->routes->toDashboard());
+it('routes to homepage', fn() => $this->routes->toHomepage());
+it('routes to login', fn() => $this->routes->toLogin());
+it('routes to logout', fn() => $this->routes->toLogout());
+it('routes to register', fn() => $this->routes->toRegister());
+it('routes to password confirm', fn() => $this->routes->toPasswordConfirm());
+it('routes to password request', fn() => $this->routes->toPasswordRequest());
+it('routes to password email', fn() => $this->routes->toPasswordEmail());
+it('routes to password update', fn() => $this->routes->toPasswordUpdate());
+it('routes to password store', fn() => $this->routes->toPasswordStore());
+it('routes to password reset', fn() => $this->routes->toPasswordReset());
+it('routes to profile edit', fn() => $this->routes->toProfileEdit());
+it('routes to profile update', fn() => $this->routes->toProfileUpdate());
+it('routes to profile destroy', fn() => $this->routes->toProfileDestroy());
+it('routes to verification send', fn() => $this->routes->toVerificationSend());
+it('routes to verification notice', fn() => $this->routes->toVerificationNotice());
+it('routes to verification verify', fn() => $this->routes->toVerificationVerify());
+
+/**
+ * Redirects the authenticated user to the dashboard
+ */
+it('redirects login to dashboard', fn() => $this->redirects->loginToDashboard());
+it('redirects register to dashboard', fn() => $this->redirects->registerToDashboard());
+it('redirects verification notice to dashboard', fn() => $this->redirects->verificatioNoticeToDashboard());
+it('redirects forgot password to dashboard', fn() => $this->redirects->forgotPasswordToDashboard());
+it('redirects reset password to dashboard', fn() => $this->redirects->resetPasswordToDashboard());
+
+/**
+ * Exposes the correct functionalities
+ */
+it('exposes homepage', fn() => $this->exposes->homepage());
+it('exposes dashboard', fn() => $this->exposes->dashboard());
+it('exposes error on verification verify', fn() => $this->exposes->errorPageOnVerificationVerify());
+it('exposes profile', fn() => $this->exposes->profile());
diff --git a/tests/Feature/LoggedIn/DisabledUserProfileTest.php b/tests/Feature/LoggedIn/DisabledUserProfileTest.php
new file mode 100644
index 0000000..24076a8
--- /dev/null
+++ b/tests/Feature/LoggedIn/DisabledUserProfileTest.php
@@ -0,0 +1,57 @@
+bootAuth();
+ $this->auth()->withDashboard('dashboard');
+ $this->auth()->withoutUserProfile();
+ }
+);
+
+/**
+ * All routes are available
+ */
+it('routes to dashboard', fn() => $this->routes->toDashboard());
+it('routes to homepage', fn() => $this->routes->toHomepage());
+it('routes to login', fn() => $this->routes->toLogin());
+it('routes to logout', fn() => $this->routes->toLogout());
+it('routes to register', fn() => $this->routes->toRegister());
+it('routes to password confirm', fn() => $this->routes->toPasswordConfirm());
+it('routes to password request', fn() => $this->routes->toPasswordRequest());
+it('routes to password email', fn() => $this->routes->toPasswordEmail());
+it('routes to password update', fn() => $this->routes->toPasswordUpdate());
+it('routes to password store', fn() => $this->routes->toPasswordStore());
+it('routes to password reset', fn() => $this->routes->toPasswordReset());
+it('routes to profile edit', fn() => $this->routes->toProfileEdit());
+it('routes to profile update', fn() => $this->routes->toProfileUpdate());
+it('routes to profile destroy', fn() => $this->routes->toProfileDestroy());
+it('routes to verification send', fn() => $this->routes->toVerificationSend());
+it('routes to verification notice', fn() => $this->routes->toVerificationNotice());
+it('routes to verification verify', fn() => $this->routes->toVerificationVerify());
+
+/**
+ * Redirects the authenticated user to the dashboard
+ */
+it('redirects login to dashboard', fn() => $this->redirects->loginToDashboard());
+it('redirects register to dashboard', fn() => $this->redirects->registerToDashboard());
+it('redirects verification notice to dashboard', fn() => $this->redirects->verificatioNoticeToDashboard());
+it('redirects forgot password to dashboard', fn() => $this->redirects->forgotPasswordToDashboard());
+it('redirects reset password to dashboard', fn() => $this->redirects->resetPasswordToDashboard());
+
+/**
+ * Exposes the correct functionalities
+ */
+it('exposes homepage', fn() => $this->exposes->homepage());
+it('exposes dashboard', fn() => $this->exposes->dashboard());
+it('exposes error on verification verify', fn() => $this->exposes->errorPageOnVerificationVerify());
+
+/**
+ * Hides profile without user profile enabled
+ */
+it('hides profile without user profile', fn() => $this->hides->profile());
diff --git a/tests/Feature/LoggedOut/AllEnabledTest.php b/tests/Feature/LoggedOut/AllEnabledTest.php
new file mode 100644
index 0000000..046966b
--- /dev/null
+++ b/tests/Feature/LoggedOut/AllEnabledTest.php
@@ -0,0 +1,56 @@
+bootAuth();
+ }
+);
+
+it('routes to dashboard', fn() => $this->routes->toDashboard());
+it('routes to homepage', fn() => $this->routes->toHomepage());
+it('routes to login', fn() => $this->routes->toLogin());
+it('routes to logout', fn() => $this->routes->toLogout());
+it('routes to register', fn() => $this->routes->toRegister());
+it('routes to password confirm', fn() => $this->routes->toPasswordConfirm());
+it('routes to password request', fn() => $this->routes->toPasswordRequest());
+it('routes to password email', fn() => $this->routes->toPasswordEmail());
+it('routes to password update', fn() => $this->routes->toPasswordUpdate());
+it('routes to password store', fn() => $this->routes->toPasswordStore());
+it('routes to password reset', fn() => $this->routes->toPasswordReset());
+it('routes to profile edit', fn() => $this->routes->toProfileEdit());
+it('routes to profile update', fn() => $this->routes->toProfileUpdate());
+it('routes to profile destroy', fn() => $this->routes->toProfileDestroy());
+it('routes to verification send', fn() => $this->routes->toVerificationSend());
+it('routes to verification notice', fn() => $this->routes->toVerificationNotice());
+it('routes to verification verify', fn() => $this->routes->toVerificationVerify());
+
+/**
+ * Check that the login, register, forgot password and reset password are available
+ */
+it('exposes homepage', fn() => $this->exposes->homepage());
+it('exposes login', fn() => $this->exposes->login());
+it('exposes register', fn() => $this->exposes->register());
+it('exposes forgot password', fn() => $this->exposes->forgotPassword());
+it('exposes reset password', fn() => $this->exposes->resetPassword());
+
+/**
+ * Has the correct links in the various views
+ */
+it('has register in login', fn() => $this->has->registerInLogin());
+it('has password request in login', fn() => $this->has->passwordRequestInLogin());
+it('has login in register', fn() => $this->has->loginInRegister());
+
+/**
+ * Correcly redirects to login protected routes
+ */
+it('redirects dashboard to login', fn() => $this->redirects->dashboardToLogin());
+it('redirects verification notice to login', fn() => $this->redirects->verificatioNoticeToLogin());
+it('redirects verification verify to login', fn() => $this->redirects->verificationVerifyToLogin());
+it('redirects profile to login', fn() => $this->redirects->profileToLogin());
diff --git a/tests/Feature/LoggedOut/DisabledForgotPasswordTest.php b/tests/Feature/LoggedOut/DisabledForgotPasswordTest.php
new file mode 100644
index 0000000..7e8a5b2
--- /dev/null
+++ b/tests/Feature/LoggedOut/DisabledForgotPasswordTest.php
@@ -0,0 +1,66 @@
+bootAuth();
+ $this->auth()->withoutForgotPassword();
+ }
+);
+
+it('routes to dashboard', fn() => $this->routes->toDashboard());
+it('routes to homepage', fn() => $this->routes->toHomepage());
+it('routes to login', fn() => $this->routes->toLogin());
+it('routes to logout', fn() => $this->routes->toLogout());
+it('routes to register', fn() => $this->routes->toRegister());
+it('routes to password confirm', fn() => $this->routes->toPasswordConfirm());
+it('routes to password request', fn() => $this->routes->toPasswordRequest());
+it('routes to password email', fn() => $this->routes->toPasswordEmail());
+it('routes to password update', fn() => $this->routes->toPasswordUpdate());
+it('routes to password store', fn() => $this->routes->toPasswordStore());
+it('routes to password reset', fn() => $this->routes->toPasswordReset());
+it('routes to profile edit', fn() => $this->routes->toProfileEdit());
+it('routes to profile update', fn() => $this->routes->toProfileUpdate());
+it('routes to profile destroy', fn() => $this->routes->toProfileDestroy());
+it('routes to verification send', fn() => $this->routes->toVerificationSend());
+it('routes to verification notice', fn() => $this->routes->toVerificationNotice());
+it('routes to verification verify', fn() => $this->routes->toVerificationVerify());
+
+/**
+ * Check that the login, register are available
+ */
+it('exposes homepage', fn() => $this->exposes->homepage());
+it('exposes login', fn() => $this->exposes->login());
+it('exposes register', fn() => $this->exposes->register());
+
+/**
+ * Hides forgot and reset password
+ */
+it('hides forgot password', fn() => $this->hides->forgotPassword());
+it('hides reset password', fn() => $this->hides->resetPassword());
+
+/**
+ * Has the correct links in the various views
+ */
+it('has register in login', fn() => $this->has->registerInLogin());
+it('has login in register', fn() => $this->has->loginInRegister());
+
+/**
+ * Hasn't the link to forgot password in the login
+ */
+
+it('has not password request in login', fn() => $this->hasNot->passwordRequestInLogin());
+
+/**
+ * Correcly redirects to login protected routes
+ */
+it('redirects dashboard to login', fn() => $this->redirects->dashboardToLogin());
+it('redirects verification notice to login', fn() => $this->redirects->verificatioNoticeToLogin());
+it('redirects verification verify to login', fn() => $this->redirects->verificationVerifyToLogin());
+it('redirects profile to login', fn() => $this->redirects->profileToLogin());
diff --git a/tests/Feature/LoggedOut/DisabledRegistrationTest.php b/tests/Feature/LoggedOut/DisabledRegistrationTest.php
new file mode 100644
index 0000000..f011d20
--- /dev/null
+++ b/tests/Feature/LoggedOut/DisabledRegistrationTest.php
@@ -0,0 +1,64 @@
+bootAuth();
+ $this->auth()->withoutRegistration();
+ }
+);
+
+it('routes to dashboard', fn() => $this->routes->toDashboard());
+it('routes to homepage', fn() => $this->routes->toHomepage());
+it('routes to login', fn() => $this->routes->toLogin());
+it('routes to logout', fn() => $this->routes->toLogout());
+it('routes to register', fn() => $this->routes->toRegister());
+it('routes to password confirm', fn() => $this->routes->toPasswordConfirm());
+it('routes to password request', fn() => $this->routes->toPasswordRequest());
+it('routes to password email', fn() => $this->routes->toPasswordEmail());
+it('routes to password update', fn() => $this->routes->toPasswordUpdate());
+it('routes to password store', fn() => $this->routes->toPasswordStore());
+it('routes to password reset', fn() => $this->routes->toPasswordReset());
+it('routes to profile edit', fn() => $this->routes->toProfileEdit());
+it('routes to profile update', fn() => $this->routes->toProfileUpdate());
+it('routes to profile destroy', fn() => $this->routes->toProfileDestroy());
+it('routes to verification send', fn() => $this->routes->toVerificationSend());
+it('routes to verification notice', fn() => $this->routes->toVerificationNotice());
+it('routes to verification verify', fn() => $this->routes->toVerificationVerify());
+
+/**
+ * Check that the login, forgot password and reset password are available
+ */
+it('exposes homepage', fn() => $this->exposes->homepage());
+it('exposes login', fn() => $this->exposes->login());
+it('exposes forgot password', fn() => $this->exposes->forgotPassword());
+it('exposes reset password', fn() => $this->exposes->resetPassword());
+
+/**
+ * Check that the register is not available
+ */
+it('hides register', fn() => $this->hides->register());
+
+/**
+ * Has the correct links in the various views
+ */
+it('has password request in login', fn() => $this->has->passwordRequestInLogin());
+
+/**
+ * Hasn't the correct links in the various views
+ */
+it('has not register in login', fn() => $this->hasNot->registerInLogin());
+
+/**
+ * Correcly redirects to login protected routes
+ */
+it('redirects dashboard to login', fn() => $this->redirects->dashboardToLogin());
+it('redirects verification notice to login', fn() => $this->redirects->verificatioNoticeToLogin());
+it('redirects verification verify to login', fn() => $this->redirects->verificationVerifyToLogin());
+it('redirects profile to login', fn() => $this->redirects->profileToLogin());
diff --git a/tests/Feature/Unverified/AllEnabledTest.php b/tests/Feature/Unverified/AllEnabledTest.php
new file mode 100644
index 0000000..75501c5
--- /dev/null
+++ b/tests/Feature/Unverified/AllEnabledTest.php
@@ -0,0 +1,52 @@
+bootAuth();
+ $this->auth()->withDashboard('dashboard');
+ }
+);
+
+/**
+ * All routes are available
+ */
+it('routes to dashboard', fn() => $this->routes->toDashboard());
+it('routes to homepage', fn() => $this->routes->toHomepage());
+it('routes to login', fn() => $this->routes->toLogin());
+it('routes to logout', fn() => $this->routes->toLogout());
+it('routes to register', fn() => $this->routes->toRegister());
+it('routes to password confirm', fn() => $this->routes->toPasswordConfirm());
+it('routes to password request', fn() => $this->routes->toPasswordRequest());
+it('routes to password email', fn() => $this->routes->toPasswordEmail());
+it('routes to password update', fn() => $this->routes->toPasswordUpdate());
+it('routes to password store', fn() => $this->routes->toPasswordStore());
+it('routes to password reset', fn() => $this->routes->toPasswordReset());
+it('routes to profile edit', fn() => $this->routes->toProfileEdit());
+it('routes to profile update', fn() => $this->routes->toProfileUpdate());
+it('routes to profile destroy', fn() => $this->routes->toProfileDestroy());
+it('routes to verification send', fn() => $this->routes->toVerificationSend());
+it('routes to verification notice', fn() => $this->routes->toVerificationNotice());
+it('routes to verification verify', fn() => $this->routes->toVerificationVerify());
+
+/**
+ * Redirects the authenticated user to the dashboard
+ */
+it('redirects login to dashboard', fn() => $this->redirects->loginToDashboard());
+it('redirects register to dashboard', fn() => $this->redirects->registerToDashboard());
+it('redirects forgot password to dashboard', fn() => $this->redirects->forgotPasswordToDashboard());
+it('redirects reset password to dashboard', fn() => $this->redirects->resetPasswordToDashboard());
+it('redirects profile to verification notice', fn() => $this->redirects->profileToVerificationNotice());
+it('redirects dashboard to verification notice', fn() => $this->redirects->dashboardToVerificationNotice());
+
+/**
+ * Exposes the correct functionalities
+ */
+it('exposes homepage', fn() => $this->exposes->homepage());
+it('exposes verification notice', fn() => $this->exposes->verificatioNotice());
+it('exposes error on verification verify', fn() => $this->exposes->errorPageOnVerificationVerify());
diff --git a/tests/Feature/Unverified/DisabledVerificationTest.php b/tests/Feature/Unverified/DisabledVerificationTest.php
new file mode 100644
index 0000000..a39e43c
--- /dev/null
+++ b/tests/Feature/Unverified/DisabledVerificationTest.php
@@ -0,0 +1,58 @@
+bootAuth();
+ $this->auth()->withDashboard('dashboard');
+ $this->auth()->withoutEmailVerification();
+ }
+);
+
+/**
+ * All routes are available
+ */
+it('routes to dashboard', fn() => $this->routes->toDashboard());
+it('routes to homepage', fn() => $this->routes->toHomepage());
+it('routes to login', fn() => $this->routes->toLogin());
+it('routes to logout', fn() => $this->routes->toLogout());
+it('routes to register', fn() => $this->routes->toRegister());
+it('routes to password confirm', fn() => $this->routes->toPasswordConfirm());
+it('routes to password request', fn() => $this->routes->toPasswordRequest());
+it('routes to password email', fn() => $this->routes->toPasswordEmail());
+it('routes to password update', fn() => $this->routes->toPasswordUpdate());
+it('routes to password store', fn() => $this->routes->toPasswordStore());
+it('routes to password reset', fn() => $this->routes->toPasswordReset());
+it('routes to profile edit', fn() => $this->routes->toProfileEdit());
+it('routes to profile update', fn() => $this->routes->toProfileUpdate());
+it('routes to profile destroy', fn() => $this->routes->toProfileDestroy());
+it('routes to verification send', fn() => $this->routes->toVerificationSend());
+it('routes to verification notice', fn() => $this->routes->toVerificationNotice());
+it('routes to verification verify', fn() => $this->routes->toVerificationVerify());
+
+/**
+ * Redirects the authenticated user to the dashboard
+ */
+it('redirects login to dashboard', fn() => $this->redirects->loginToDashboard());
+it('redirects register to dashboard', fn() => $this->redirects->registerToDashboard());
+it('redirects forgot password to dashboard', fn() => $this->redirects->forgotPasswordToDashboard());
+it('redirects reset password to dashboard', fn() => $this->redirects->resetPasswordToDashboard());
+
+/**
+ * Exposes the correct functionalities
+ */
+it('exposes homepage', fn() => $this->exposes->homepage());
+it('exposes dashboard', fn() => $this->exposes->dashboard());
+it('exposes profile', fn() => $this->exposes->profile());
+
+/**
+ * Hides the correct functionalities
+ */
+it('hides verification notice', fn() => $this->hides->verificationNotice());
+it('hides verification send', fn() => $this->hides->verificationSend());
+it('hides verification verify', fn() => $this->hides->verificationVerify());
diff --git a/tests/FeatureHelpers/Contracts/Helper.php b/tests/FeatureHelpers/Contracts/Helper.php
new file mode 100644
index 0000000..44f311d
--- /dev/null
+++ b/tests/FeatureHelpers/Contracts/Helper.php
@@ -0,0 +1,25 @@
+user ? test() : actingAs($this->user, $guard);
+ }
+}
\ No newline at end of file
diff --git a/tests/FeatureHelpers/Exposes.php b/tests/FeatureHelpers/Exposes.php
new file mode 100644
index 0000000..3686fe5
--- /dev/null
+++ b/tests/FeatureHelpers/Exposes.php
@@ -0,0 +1,128 @@
+testCase()->get(route('homepage'))
+ ->assertOk()
+ ->assertSee('This is a dummy home');
+ }
+
+ /**
+ * The dummy dashboard - defined in the test suite - should be available
+ */
+ public function dashboard(): void
+ {
+ $this->testCase()->get(route('dashboard'))
+ ->assertOk()
+ ->assertSee('This is a dummy dashboard');
+ }
+
+ /**
+ * Login should be available
+ */
+ public function login(): void
+ {
+ $this->testCase()->get(route($this->auth->route_login))
+ ->assertOk() // Should be 200
+ ->assertSee('name="email"', false) // Email field should be present
+ ->assertSee('name="password"', false) // Password field should be present
+ ->assertSee('type="submit"', false) // Login button should be present
+ ;
+ }
+
+ /**
+ * Register should be available
+ */
+ public function register(): void
+ {
+ $this->testCase()->get(route($this->auth->route_register))
+ ->assertOk() // Should be 200
+ ->assertSee('name="name"', false) // Name field should be present
+ ->assertSee('name="email"', false) // Email field should be present
+ ->assertSee('name="password"', false) // Password field should be present
+ ->assertSee('name="password_confirmation"', false) // Confirm Password field should be present
+ ->assertSee('type="submit"', false) // Register button should be present
+ ;
+ }
+
+ /**
+ * Forgot password should be available
+ */
+ public function forgotPassword(): void
+ {
+ $this->testCase()->get(route($this->auth->route_password_request))
+ ->assertOk() // Should be 200
+ ->assertSee('name="email"', false) // Email field should be present
+ ->assertSee('type="submit"', false) // Send Password Reset Link button should be present
+ ;
+ }
+
+ /**
+ * Reset password should be available
+ */
+ public function resetPassword(): void
+ {
+ $this->testCase()->get(route($this->auth->route_password_reset, ['token' => 'wrong']))
+ ->assertOk() // Should be 200
+ ->assertSee('name="email"', false) // Email field should be present
+ ->assertSee('name="password"', false) // Password field should be present
+ ->assertSee('name="password_confirmation"', false) // Confirm Password field should be present
+ ->assertSee('type="submit"', false) // Send Password Reset Link button should be present
+ ;
+ }
+
+ /**
+ * Verification notice should be available
+ */
+ public function verificatioNotice(): void
+ {
+ $this->testCase()->get(route($this->auth->route_verification_notice))
+ ->assertOk() // Should be 200
+ ;
+ }
+
+ /**
+ * The Verification verify page should be available
+ */
+ public function verificationVerify(): void
+ {
+ $this->testCase()->get(route($this->auth->route_verification_verify, ['id' => 1, 'hash' => 'wrong']))
+ ->assertOk() // Should be 200
+ ;
+ }
+
+ /**
+ * The Verification verify page should return a 403 error
+ */
+ public function errorPageOnVerificationVerify(): void
+ {
+ $this->testCase()->get(route($this->auth->route_verification_verify, ['id' => 1, 'hash' => 'wrong']))
+ ->assertStatus(403);
+ ;
+ }
+
+ /**
+ * The profile should be available
+ */
+ public function profile(): void
+ {
+ $this->testCase()->get(route($this->auth->route_profile_edit))
+ ->assertOk() // Should be 200
+ ->assertSee('name="name"', false) // Name field should be present
+ ->assertSee('name="email"', false) // Email field should be present
+ ->assertSee(route($this->auth->route_profile_update), false) // Update profile form should be present
+ ->assertSee(route($this->auth->route_password_update), false) // Update password form should be present
+ ->assertSee(route($this->auth->route_profile_destroy), false) // Delete profile form should be present
+ ->assertSee(route($this->auth->route_logout), false) // Logout button should be present
+ ;
+ }
+}
diff --git a/tests/FeatureHelpers/Has.php b/tests/FeatureHelpers/Has.php
new file mode 100644
index 0000000..d0ce36b
--- /dev/null
+++ b/tests/FeatureHelpers/Has.php
@@ -0,0 +1,27 @@
+testCase()->get(route($this->auth->route_login))
+ ->assertSee(route($this->auth->route_register));
+ }
+
+ public function passwordRequestInLogin(): void
+ {
+ $this->testCase()->get(route($this->auth->route_login))
+ ->assertSee(route($this->auth->route_password_request));
+ }
+
+ public function loginInRegister(): void
+ {
+ $this->testCase()->get(route($this->auth->route_register))
+ ->assertSee(route($this->auth->route_login));
+ }
+}
\ No newline at end of file
diff --git a/tests/FeatureHelpers/HasNot.php b/tests/FeatureHelpers/HasNot.php
new file mode 100644
index 0000000..a44b686
--- /dev/null
+++ b/tests/FeatureHelpers/HasNot.php
@@ -0,0 +1,21 @@
+testCase()->get(route($this->auth->route_login))
+ ->assertDontSee(route($this->auth->route_register));
+ }
+
+ public function passwordRequestInLogin(): void
+ {
+ $this->testCase()->get(route($this->auth->route_login))
+ ->assertDontSee(route($this->auth->route_password_request));
+ }
+}
\ No newline at end of file
diff --git a/tests/FeatureHelpers/Hides.php b/tests/FeatureHelpers/Hides.php
new file mode 100644
index 0000000..2e1c06a
--- /dev/null
+++ b/tests/FeatureHelpers/Hides.php
@@ -0,0 +1,89 @@
+testCase()->get(route($this->auth->route_register))
+ ->assertNotFound() // Should be 404
+ ;
+ }
+
+ /**
+ * Forgot password should be available
+ */
+ public function forgotPassword(): void
+ {
+ $this->testCase()->get(route($this->auth->route_password_request))
+ ->assertNotFound() // Should be 404
+ ;
+ }
+
+ /**
+ * Reset password should be available
+ */
+ public function resetPassword(): void
+ {
+ $this->testCase()->get(route($this->auth->route_password_reset, ['token' => 'wrong']))
+ ->assertNotFound() // Should be 404
+ ;
+ }
+
+ /**
+ * Profile should not be available
+ */
+ public function profile(): void
+ {
+ $this->testCase()->get(route($this->auth->route_profile_edit))
+ ->assertNotFound() // Should be 404
+ ;
+ }
+
+ /**
+ * The dashboard - defined in the test suite - should not be available
+ */
+ public function dashboard(): void
+ {
+ $this->testCase()->get(route('dashboard'))
+ ->assertNotFound() // Should be 404
+ ;
+ }
+
+ /**
+ * Hides the verification notice route
+ */
+ public function verificationNotice(): void
+ {
+ $this->testCase()->get(route($this->auth->route_verification_notice))
+ ->assertNotFound() // Should be 404
+ ;
+ }
+
+ /**
+ * Hides the verification send route
+ */
+ public function verificationSend(): void
+ {
+ $this->testCase()->post(route($this->auth->route_verification_send))
+ ->assertNotFound() // Should be 404
+ ;
+ }
+
+ /**
+ * Hides the verification verify route
+ */
+ public function verificationVerify(): void
+ {
+ $this->testCase()->get(route($this->auth->route_verification_verify, ['id' => 1, 'hash' => 'wrong']))
+ ->assertNotFound() // Should be 404
+ ;
+ }
+}
\ No newline at end of file
diff --git a/tests/FeatureHelpers/Providers/AuthServiceProvider.php b/tests/FeatureHelpers/Providers/AuthServiceProvider.php
new file mode 100644
index 0000000..c1b8005
--- /dev/null
+++ b/tests/FeatureHelpers/Providers/AuthServiceProvider.php
@@ -0,0 +1,20 @@
+middleware_web)
+ ->get('/homepage', fn() => 'This is a dummy home')
+ ->name('homepage');
+
+ /**
+ * A dummy dashboard route, protected
+ */
+ Route::middleware(InsideAuth::getAuthenticator('test')->middleware_verified)
+ ->get('/dashboard', fn() => 'This is a dummy dashboard')
+ ->name('dashboard');
+ }
+}
diff --git a/tests/FeatureHelpers/Redirects.php b/tests/FeatureHelpers/Redirects.php
new file mode 100644
index 0000000..d6a7df0
--- /dev/null
+++ b/tests/FeatureHelpers/Redirects.php
@@ -0,0 +1,111 @@
+testCase()->get(route('dashboard'))
+ ->assertRedirect(route($this->auth->route_login));
+ }
+
+ /**
+ * The Verification notice should redirect to login
+ */
+ public function verificatioNoticeToLogin(): void
+ {
+ $this->testCase()->get(route($this->auth->route_verification_notice))
+ ->assertRedirect(route($this->auth->route_login));
+ }
+
+ /**
+ * The Verification verify should redirect to login if id and hash are wrong
+ */
+ public function verificationVerifyToLogin(): void
+ {
+ $this->testCase()->get(route($this->auth->route_verification_verify, ['id' => 1, 'hash' => 'wrong']))
+ ->assertRedirect(route($this->auth->route_login));
+ }
+
+ /**
+ * All profile routes should redirect to login
+ */
+ public function profileToLogin(): void
+ {
+ $this->testCase()->get(route($this->auth->route_profile_edit))
+ ->assertRedirect(route($this->auth->route_login));
+ $this->testCase()->get(route($this->auth->route_profile_update))
+ ->assertRedirect(route($this->auth->route_login));
+ $this->testCase()->get(route($this->auth->route_profile_destroy))
+ ->assertRedirect(route($this->auth->route_login));
+ }
+ /**
+ * The login should redirect to dashboard if logged in
+ */
+ public function loginToDashboard(): void
+ {
+ $this->testCase()->get(route($this->auth->route_login))
+ ->assertRedirect(route('dashboard'));
+ }
+
+ /**
+ * The register should redirect to dashboard if logged in
+ */
+ public function registerToDashboard(): void
+ {
+ $this->testCase()->get(route($this->auth->route_register))
+ ->assertRedirect(route('dashboard'));
+ }
+
+ /**
+ * The verification notice should redirect to dashboard if logged in
+ */
+ public function verificatioNoticeToDashboard(): void
+ {
+ $this->testCase()->get(route($this->auth->route_verification_notice))
+ ->assertRedirect(route('dashboard'));
+ }
+
+ /**
+ * The verification verify should redirect to dashboard if logged in
+ */
+ public function forgotPasswordToDashboard(): void
+ {
+ $this->testCase()->get(route($this->auth->route_password_request))
+ ->assertRedirect(route('dashboard'));
+ }
+
+ /**
+ * The reset password should redirect to dashboard if logged in
+ */
+ public function resetPasswordToDashboard(): void
+ {
+ $this->testCase()->get(route($this->auth->route_password_reset, ['token' => 'wrong']))
+ ->assertRedirect(route('dashboard'));
+ }
+
+ /**
+ * The dashboard should redirect to verification notice if not verified
+ */
+ public function dashboardToVerificationNotice(): void
+ {
+ $this->testCase()->get(route('dashboard'))
+ ->assertRedirect(route($this->auth->route_verification_notice));
+ }
+
+ /**
+ * The profile should redirect to verification notice if not verified
+ */
+ public function profileToVerificationNotice(): void
+ {
+ $this->testCase()->get(route($this->auth->route_profile_edit))
+ ->assertRedirect(route($this->auth->route_verification_notice));
+ }
+}
\ No newline at end of file
diff --git a/tests/FeatureHelpers/Routes.php b/tests/FeatureHelpers/Routes.php
new file mode 100644
index 0000000..d6a56ff
--- /dev/null
+++ b/tests/FeatureHelpers/Routes.php
@@ -0,0 +1,178 @@
+toBe('/homepage');
+ }
+
+ /**
+ * The route to the dummy dashboard is correct
+ */
+ public function toDashboard(): void
+ {
+ expect(
+ route('dashboard', [], false)
+ )->toBe('/dashboard');
+ }
+
+ /**
+ * The route to login is correct
+ */
+ public function toLogin(): void
+ {
+ expect(
+ route($this->auth->route_login, [], false)
+ )->toBe('/' . $this->auth->name() . '/login');
+ }
+
+ /**
+ * The route to logout is correct
+ */
+ public function toLogout(): void
+ {
+ expect(
+ route($this->auth->route_logout, [], false)
+ )->toBe('/' . $this->auth->name() . '/logout');
+ }
+
+ /**
+ * The route to register is correct
+ */
+ public function toRegister(): void
+ {
+ expect(
+ route($this->auth->route_register, [], false)
+ )->toBe('/' . $this->auth->name() . '/register');
+ }
+
+ /**
+ * The route to the password confirm is correct
+ */
+ public function toPasswordConfirm(): void
+ {
+ expect(
+ route($this->auth->route_password_confirm, [], false)
+ )->toBe('/' . $this->auth->name() . '/confirm-password');
+ }
+
+ /**
+ * The route to the password request is correct
+ */
+ public function toPasswordRequest(): void
+ {
+ expect(
+ route($this->auth->route_password_request, [], false)
+ )->toBe('/' . $this->auth->name() . '/forgot-password');
+ }
+
+ /**
+ * The route to the password email is correct
+ */
+ public function toPasswordEmail(): void
+ {
+ expect(
+ route($this->auth->route_password_email, [], false)
+ )->toBe('/' . $this->auth->name() . '/forgot-password');
+ }
+
+ /**
+ * The route to the password update is correct
+ */
+ public function toPasswordUpdate(): void
+ {
+ expect(
+ route($this->auth->route_password_update, [], false)
+ )->toBe('/' . $this->auth->name() . '/password');
+ }
+
+ /**
+ * The route to the password store is correct
+ */
+ public function toPasswordStore(): void
+ {
+ expect(
+ route($this->auth->route_password_store, [], false)
+ )->toBe('/' . $this->auth->name() . '/reset-password');
+ }
+
+ /**
+ * The route to the password reset is correct
+ */
+ public function toPasswordReset(): void
+ {
+ expect(
+ route($this->auth->route_password_reset, ['token' => 'test'], false)
+ )->toBe('/' . $this->auth->name() . '/reset-password/test');
+ }
+
+ /**
+ * The route to the profile edit is correct
+ */
+ public function toProfileEdit(): void
+ {
+ expect(
+ route($this->auth->route_profile_edit, [], false)
+ )->toBe('/' . $this->auth->name() . '/profile');
+ }
+
+ /**
+ * The route to the profile update is correct
+ */
+ public function toProfileUpdate(): void
+ {
+ expect(
+ route($this->auth->route_profile_update, [], false)
+ )->toBe('/' . $this->auth->name() . '/profile');
+ }
+
+ /**
+ * The route to the profile destroy is correct
+ */
+ public function toProfileDestroy(): void
+ {
+ expect(
+ route($this->auth->route_profile_destroy, [], false)
+ )->toBe('/' . $this->auth->name() . '/profile');
+ }
+
+ /**
+ * The route to the verification send is correct
+ */
+ public function toVerificationSend(): void
+ {
+ expect(
+ route($this->auth->route_verification_send, [], false)
+ )->toBe('/' . $this->auth->name() . '/email/verification-notification');
+ }
+
+ /**
+ * The route to the verification notice is correct
+ */
+ public function toVerificationNotice(): void
+ {
+ expect(
+ route($this->auth->route_verification_notice, [], false)
+ )->toBe('/' . $this->auth->name() . '/verify-email');
+ }
+
+ /**
+ * The route to the verification verify is correct
+ */
+ public function toVerificationVerify(): void
+ {
+ expect(
+ route($this->auth->route_verification_verify, ['id' => 1, 'hash' => 'test'], false)
+ )->toBe('/' . $this->auth->name() . '/verify-email/1/test');
+ }
+}
diff --git a/tests/LoggedInFeatureTestCase.php b/tests/LoggedInFeatureTestCase.php
new file mode 100644
index 0000000..073b801
--- /dev/null
+++ b/tests/LoggedInFeatureTestCase.php
@@ -0,0 +1,35 @@
+create();
+
+ $authenticator = InsideAuth::getAuthenticator(AuthServiceProvider::AUTH_NAME);
+ $this->exposes = new Exposes($authenticator, $user);
+ $this->redirects = new Redirects($authenticator, $user);
+ $this->routes = new Routes($authenticator, $user);
+ $this->has = new Has($authenticator, $user);
+ $this->hasNot = new HasNot($authenticator, $user);
+ $this->hides = new Hides($authenticator, $user);
+ }
+}
\ No newline at end of file
diff --git a/tests/LoggedOutFeatureTestCase.php b/tests/LoggedOutFeatureTestCase.php
new file mode 100644
index 0000000..a3e53e7
--- /dev/null
+++ b/tests/LoggedOutFeatureTestCase.php
@@ -0,0 +1,88 @@
+exposes = new Exposes($authenticator);
+ $this->redirects = new Redirects($authenticator);
+ $this->routes = new Routes($authenticator);
+ $this->has = new Has($authenticator);
+ $this->hasNot = new HasNot($authenticator);
+ $this->hides = new Hides($authenticator);
+ }
+
+ /**
+ * Returns the Authenticator
+ */
+ protected function auth(): Authenticator
+ {
+ return InsideAuth::getAuthenticator(AuthServiceProvider::AUTH_NAME);
+ }
+
+ /**
+ * Returns the package providers needed for the tests
+ */
+ protected function getPackageProviders($app): array
+ {
+ return [
+ ServiceProvider::class,
+ AuthServiceProvider::class,
+ RouteServiceProvider::class
+ ];
+ }
+
+ /**
+ * @throws ContainerExceptionInterface
+ * @throws NotFoundExceptionInterface
+ */
+ protected function getEnvironmentSetUp($app)
+ {
+ $config = $app->get('config');
+ $config->set('logging.default', 'errorlog');
+ $config->set('database.default', 'testbench');
+ $config->set('database.connections.testbench', [
+ 'driver' => 'sqlite',
+ 'database' => ':memory:',
+ 'prefix' => '',
+ ]);
+ }
+}
diff --git a/tests/Pest.php b/tests/Pest.php
new file mode 100644
index 0000000..e212b47
--- /dev/null
+++ b/tests/Pest.php
@@ -0,0 +1,48 @@
+in('Feature/LoggedOut');
+uses(LoggedInFeatureTestCase::class)->in('Feature/LoggedIn');
+uses(UnverifiedFeatureTestCase::class)->in('Feature/Unverified');
+uses(TestCase::class)->in('Unit');
+
+/*
+|--------------------------------------------------------------------------
+| Expectations
+|--------------------------------------------------------------------------
+|
+| When you're writing tests, you often need to check that values meet certain conditions. The
+| "expect()" function gives you access to a set of "expectations" methods that you can use
+| to assert different things. Of course, you may extend the Expectation API at any time.
+|
+*/
+
+expect()->extend('toBeOne', function () {
+ return $this->toBe(1);
+});
+
+/*
+|--------------------------------------------------------------------------
+| Functions
+|--------------------------------------------------------------------------
+|
+| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
+| project that you don't want to repeat in every file. Here you can also expose helpers as
+| global functions to help you to reduce the number of lines of code in your test files.
+|
+*/
diff --git a/tests/Unit/AuthenticatorTest.php b/tests/Unit/AuthenticatorTest.php
new file mode 100644
index 0000000..33ceb0c
--- /dev/null
+++ b/tests/Unit/AuthenticatorTest.php
@@ -0,0 +1,142 @@
+authenticator = new Authenticator('auth');
+});
+
+test('The authenticator has the correct class', function () {
+ expect($this->authenticator)->toBeInstanceOf(Authenticator::class);
+});
+
+test('Parameters are a Collection', function () {
+ expect($this->authenticator->parameters)->toBeInstanceOf(Collection::class);
+});
+
+test('Expect the correct number of parameters', function () {
+ expect($this->authenticator->parameters->count())->toBe(14);
+});
+
+test('The authenticator defaults are correct', function () {
+ expect($this->authenticator->enabled)->toBeTrue()
+ ->and($this->authenticator->registration_enabled)->toBeTrue()
+ ->and($this->authenticator->forgot_password_enabled)->toBeTrue()
+ ->and($this->authenticator->email_verification_enabled)->toBeTrue()
+ ->and($this->authenticator->user_profile_enabled)->toBeTrue()
+ ->and($this->authenticator->dashboard)->toBeNull()
+ ->and($this->authenticator->homepage)->toBeNull()
+ ->and($this->authenticator->template_confirm_password)->toBe('inside_auth::auth.confirm-password')
+ ->and($this->authenticator->template_forgot_password)->toBe('inside_auth::auth.forgot-password')
+ ->and($this->authenticator->template_login)->toBe('inside_auth::auth.login')
+ ->and($this->authenticator->template_register)->toBe('inside_auth::auth.register')
+ ->and($this->authenticator->template_reset_password)->toBe('inside_auth::auth.reset-password')
+ ->and($this->authenticator->template_verify_email)->toBe('inside_auth::auth.verify-email')
+ ->and($this->authenticator->template_profile_edit)->toBe('inside_auth::profile.edit');
+});
+
+test('The name of the authenticator is correct', function () {
+ expect($this->authenticator->name())->toBe('auth');
+});
+
+test('The authenticator can be disabled', function () {
+ expect()
+ ->and($this->authenticator->enabled(false))->toBe($this->authenticator)
+ ->and($this->authenticator->enabled)->toBeFalse()
+ ->and($this->authenticator->enabled())->toBe($this->authenticator)
+ ->and($this->authenticator->enabled)->toBeTrue();
+});
+
+test('The registration can be disabled', function () {
+ expect()
+ ->and($this->authenticator->withoutRegistration())->toBe($this->authenticator)
+ ->and($this->authenticator->registration_enabled)->toBeFalse()
+ ->and($this->authenticator->withoutRegistration(false))->toBe($this->authenticator)
+ ->and($this->authenticator->registration_enabled)->toBeTrue();
+});
+
+test('The forgot password can be disabled', function () {
+ expect()
+ ->and($this->authenticator->withoutForgotPassword())->toBe($this->authenticator)
+ ->and($this->authenticator->forgot_password_enabled)->toBeFalse()
+ ->and($this->authenticator->withoutForgotPassword(false))->toBe($this->authenticator)
+ ->and($this->authenticator->forgot_password_enabled)->toBeTrue();
+});
+
+test('The email verification can be disabled', function () {
+ expect()
+ ->and($this->authenticator->withoutEmailVerification())->toBe($this->authenticator)
+ ->and($this->authenticator->email_verification_enabled)->toBeFalse()
+ ->and($this->authenticator->withoutEmailVerification(false))->toBe($this->authenticator)
+ ->and($this->authenticator->email_verification_enabled)->toBeTrue();
+});
+
+test('The user profile can be disabled', function () {
+ expect()
+ ->and($this->authenticator->withoutUserProfile())->toBe($this->authenticator)
+ ->and($this->authenticator->user_profile_enabled)->toBeFalse()
+ ->and($this->authenticator->withoutUserProfile(false))->toBe($this->authenticator)
+ ->and($this->authenticator->user_profile_enabled)->toBeTrue();
+});
+
+test('The dashboard can be set', function () {
+ expect()
+ ->and($this->authenticator->withDashboard('dashboard'))->toBe($this->authenticator)
+ ->and($this->authenticator->dashboard)->toBe('dashboard');
+});
+
+test('The homepage can be set', function() {
+ expect()
+ ->and($this->authenticator->withHomepage('homepage'))->toBe($this->authenticator)
+ ->and($this->authenticator->homepage)->toBe('homepage');
+});
+
+test('The confirm password template can be set', function () {
+ expect()
+ ->and($this->authenticator->withConfirmPasswordTemplate('confirm-password'))->toBe($this->authenticator)
+ ->and($this->authenticator->template_confirm_password)->toBe('confirm-password');
+});
+
+test('The forgot password template can be set', function () {
+ expect()
+ ->and($this->authenticator->withForgotPasswordTemplate('forgot-password'))->toBe($this->authenticator)
+ ->and($this->authenticator->template_forgot_password)->toBe('forgot-password');
+});
+
+test('The login template can be set', function () {
+ expect()
+ ->and($this->authenticator->withLoginTemplate('login'))->toBe($this->authenticator)
+ ->and($this->authenticator->template_login)->toBe('login');
+});
+
+test('The register template can be set', function () {
+ expect()
+ ->and($this->authenticator->withRegisterTemplate('register'))->toBe($this->authenticator)
+ ->and($this->authenticator->template_register)->toBe('register');
+});
+
+test('The reset password template can be set', function () {
+ expect()
+ ->and($this->authenticator->withResetPasswordTemplate('reset-password'))->toBe($this->authenticator)
+ ->and($this->authenticator->template_reset_password)->toBe('reset-password');
+});
+
+test('The verify email template can be set', function () {
+ expect()
+ ->and($this->authenticator->withVerifyEmailTemplate('verify-email'))->toBe($this->authenticator)
+ ->and($this->authenticator->template_verify_email)->toBe('verify-email');
+});
+
+test('The profile edit template can be set', function () {
+ expect()
+ ->and($this->authenticator->withProfileEditTemplate('profile-edit'))->toBe($this->authenticator)
+ ->and($this->authenticator->template_profile_edit)->toBe('profile-edit');
+});
+
+test('Array properties can be merged', function () {
+ expect()
+ ->and($this->authenticator->merge(['test' => 'dummy']))->toBe($this->authenticator)
+ ->and($this->authenticator->test)->toBe('dummy');
+});
diff --git a/tests/Unit/Registrators/MiddlewareRegistratorTest.php b/tests/Unit/Registrators/MiddlewareRegistratorTest.php
new file mode 100644
index 0000000..37346d9
--- /dev/null
+++ b/tests/Unit/Registrators/MiddlewareRegistratorTest.php
@@ -0,0 +1,96 @@
+withAuthName($authName);
+
+ $parameters = $middlewareRegistrator->collectAndMergeParameters();
+
+ expect($parameters)->toBeInstanceOf(Collection::class)
+ ->and($parameters->toArray())->toMatchArray([
+ 'middleware_verified' => $authName . '-verified',
+ 'middleware_guest' => $authName . '-guest',
+ 'middleware_logged_in' => $authName . '-logged',
+ 'middleware_web' => $authName . '-web'
+ ]);
+
+ $router->shouldReceive('aliasMiddleware')->withArgs(function ($alias, $class) use ($authName) {
+
+ expect($alias)->toBeIn([
+ $authName . '-authenticated',
+ $authName . '-ensure-email-is-verified',
+ $authName . '-ensure-auth-is-enabled',
+ $authName . '-redirect-if-authenticated',
+ $authName . '-inject'
+ ])->and($class)
+ ->when($alias === $authName . "-authenticated", fn(Pest\Expectation $class) => $class->toBe(Authenticate::class))
+ ->when($alias === $authName . "-ensure-email-is-verified", fn(Pest\Expectation $class) => $class->toBe(EnsureEmailIsVerified::class))
+ ->when($alias === $authName . "-ensure-auth-is-enabled", fn(Pest\Expectation $class) => $class->toBe(EnsureAuthIsEnabled::class))
+ ->when($alias === $authName . "-redirect-if-authenticated", fn(Pest\Expectation $class) => $class->toBe(RedirectIfAuthenticated::class))
+ ->when($alias === $authName . "-inject", fn(Pest\Expectation $class) => $class->toBe(InjectIntoApplication::class));;
+
+ return true;
+ })->times(5);
+
+ $router->shouldReceive('middlewareGroup')->withArgs([
+ $authName . '-web',
+ [
+ EncryptCookies::class,
+ AddQueuedCookiesToResponse::class,
+ StartSession::class,
+ ShareErrorsFromSession::class,
+ VerifyCsrfToken::class,
+ SubstituteBindings::class
+ ]
+ ]);
+
+ $router->shouldReceive('middlewareGroup')->withArgs([
+ $authName . '-guest',
+ [
+ $authName . '-inject:' . $authName,
+ $authName . '-ensure-auth-is-enabled',
+ $authName . '-redirect-if-authenticated'
+ ]
+ ]);
+
+ $router->shouldReceive('middlewareGroup')->withArgs([
+ $authName . '-logged',
+ [
+ $authName . '-inject:' . $authName,
+ $authName . '-ensure-auth-is-enabled',
+ $authName . '-authenticated:login,guard'
+ ]
+ ]);
+
+ $router->shouldReceive('middlewareGroup')->withArgs([
+ $authName . '-verified',
+ [
+ $authName . '-logged',
+ $authName . '-ensure-email-is-verified'
+ ]
+ ]);
+
+ $middlewareRegistrator->boot(collect([
+ 'route_login' => 'login',
+ 'security_guard' => 'guard'
+ ]));
+})->with(['auth', 'test_auth', 'test-auth']);
\ No newline at end of file
diff --git a/tests/Unit/Registrators/RouteRegistratorTest.php b/tests/Unit/Registrators/RouteRegistratorTest.php
new file mode 100644
index 0000000..54e0f13
--- /dev/null
+++ b/tests/Unit/Registrators/RouteRegistratorTest.php
@@ -0,0 +1,200 @@
+shouldAllowMockingProtectedMethods();
+
+ $routeRegistrar = Mockery::mock(RouteRegistrar::class);
+
+ $routeRegistrator = ( new RouteRegistrator($config, $router) )
+ ->withAuthName($authName);
+
+ $parameters = $routeRegistrator->collectAndMergeParameters();
+
+ expect($parameters)->toBeInstanceOf(Collection::class)
+ ->and($parameters->toArray())->toMatchArray([
+ 'route_login' => $authName . '.auth.login',
+ 'route_register' => $authName . '.auth.register',
+ 'route_password_request' => $authName . '.auth.password.request',
+ 'route_password_email' => $authName . '.auth.password.email',
+ 'route_password_reset' => $authName . '.auth.password.reset',
+ 'route_password_store' => $authName . '.auth.password.store',
+ 'route_logout' => $authName . '.auth.logout',
+ 'route_verification_notice' => $authName . '.auth.verification.notice',
+ 'route_verification_verify' => $authName . '.auth.verification.verify',
+ 'route_verification_send' => $authName . '.auth.verification.send',
+ 'route_password_confirm' => $authName . '.auth.password.confirm',
+ 'route_password_update' => $authName . '.auth.password.update',
+ 'route_profile_edit' => $authName . '.auth.profile.edit',
+ 'route_profile_update' => $authName . '.auth.profile.update',
+ 'route_profile_destroy' => $authName . '.auth.profile.destroy'
+ ]);
+
+ $router->shouldReceive('getLastGroupPrefix')->andReturn($routeRegistrar);
+ $routeRegistrar->shouldReceive('prefix')->andReturn($routeRegistrar);
+ $routeRegistrar->shouldReceive('group')->with(Mockery::on(function ($callable) {
+ /**
+ * Call the internal implementation
+ */
+ if (is_callable($callable)) {
+ $callable();
+ return true;
+ }
+ return false;
+ }))->andReturn($routeRegistrar);
+ $routeRegistrar->shouldReceive('name')->andReturn($routeRegistrar);
+
+ $routeRegistrar->shouldReceive('middleware')->andReturn($routeRegistrar);
+
+ $router->shouldReceive('middleware')->withArgs([
+ 'test_middleware_web'
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('middleware')->withArgs([
+ 'test_middleware_guest'
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('middleware')->withArgs([
+ 'test_middleware_logged_in'
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('middleware')->withArgs([
+ 'test_middleware_verified'
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('middleware')->withArgs([
+ EnsureRegistrationIsEnabled::class
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('middleware')->withArgs([
+ EnsureForgotPasswordIsEnabled::class
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('middleware')->withArgs([
+ EnsureEmailVerificationIsEnabled::class
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('middleware')->withArgs([
+ EnsureUserProfileIsEnabled::class
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('get')->withArgs([
+ 'login',
+ [AuthenticatedSessionController::class, 'create']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('post')->withArgs([
+ 'login',
+ [AuthenticatedSessionController::class, 'store']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('get')->withArgs([
+ 'register',
+ [RegisteredUserController::class, 'create']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('post')->withArgs([
+ 'register',
+ [RegisteredUserController::class, 'store']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('get')->withArgs([
+ 'forgot-password',
+ [PasswordResetLinkController::class, 'create']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('post')->withArgs([
+ 'forgot-password',
+ [PasswordResetLinkController::class, 'store']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('get')->withArgs([
+ 'reset-password/{token}',
+ [NewPasswordController::class, 'create']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('post')->withArgs([
+ 'reset-password',
+ [NewPasswordController::class, 'store']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('post')->withArgs([
+ 'logout',
+ [AuthenticatedSessionController::class, 'destroy']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('get')->withArgs([
+ 'verify-email',
+ EmailVerificationPromptController::class
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('get')->withArgs([
+ 'verify-email/{id}/{hash}',
+ VerifyEmailController::class
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('post')->withArgs([
+ 'email/verification-notification',
+ [EmailVerificationNotificationController::class, 'store']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('get')->withArgs([
+ 'confirm-password',
+ [ConfirmablePasswordController::class, 'show']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('post')->withArgs([
+ 'confirm-password',
+ [ConfirmablePasswordController::class, 'store']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('put')->withArgs([
+ 'password',
+ [PasswordController::class, 'update']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('get')->withArgs([
+ '/profile',
+ [ProfileController::class, 'edit']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('patch')->withArgs([
+ '/profile',
+ [ProfileController::class, 'update']
+ ])->once()->andReturn($routeRegistrar);
+
+ $router->shouldReceive('delete')->withArgs([
+ '/profile',
+ [ProfileController::class, 'destroy']
+ ])->once()->andReturn($routeRegistrar);
+
+ $routeRegistrator->boot(collect([
+ 'middleware_web' => 'test_middleware_web',
+ 'middleware_guest' => 'test_middleware_guest',
+ 'middleware_logged_in' => 'test_middleware_logged_in',
+ 'middleware_verified' => 'test_middleware_verified',
+ ]));
+
+})->with(['auth', 'test_auth', 'test-auth']);
diff --git a/tests/Unit/Registrators/SecurityRegistratorTest.php b/tests/Unit/Registrators/SecurityRegistratorTest.php
new file mode 100644
index 0000000..682c655
--- /dev/null
+++ b/tests/Unit/Registrators/SecurityRegistratorTest.php
@@ -0,0 +1,52 @@
+withAuthName($authName);
+
+ $parameters = $securityRegistrator->collectAndMergeParameters();
+
+ expect($parameters)->toBeInstanceOf(Collection::class)
+ ->and($parameters->toArray())->toMatchArray([
+ 'security_guard' => $authName,
+ 'security_provider' => $authName,
+ 'security_password_broker' => $authName
+ ]);
+
+ $config->shouldReceive('set')->withArgs([
+ 'auth.guards.' . $authName,
+ [
+ 'driver' => 'session',
+ 'provider' => $authName
+ ]
+ ]);
+
+ $config->shouldReceive('set')->withArgs([
+ 'auth.providers.' . $authName,
+ [
+ 'driver' => 'eloquent',
+ 'model' => User::class
+ ]
+ ]);
+
+ $config->shouldReceive('set')->withArgs([
+ 'auth.passwords.' . $authName,
+ [
+ 'provider' => $authName,
+ 'table' => $authName . 'password_resets',
+ 'expire' => 60,
+ 'throttle' => 60,
+ ]
+ ]);
+
+ $securityRegistrator->boot(collect([]));
+})->with(['auth', 'test_auth', 'test-auth']);
diff --git a/tests/UnverifiedFeatureTestCase.php b/tests/UnverifiedFeatureTestCase.php
new file mode 100644
index 0000000..37bd98b
--- /dev/null
+++ b/tests/UnverifiedFeatureTestCase.php
@@ -0,0 +1,37 @@
+create([
+ 'email_verified_at' => null,
+ ]);
+
+ $authenticator = InsideAuth::getAuthenticator(AuthServiceProvider::AUTH_NAME);
+ $this->exposes = new Exposes($authenticator, $user);
+ $this->redirects = new Redirects($authenticator, $user);
+ $this->routes = new Routes($authenticator, $user);
+ $this->has = new Has($authenticator, $user);
+ $this->hasNot = new HasNot($authenticator, $user);
+ $this->hides = new Hides($authenticator, $user);
+ }
+
+}
\ No newline at end of file