mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
Tests
This commit is contained in:
@@ -27,7 +27,7 @@ return [
|
||||
],
|
||||
|
||||
'messages' => [
|
||||
'throttled' => 'Too many reset attempts. Please try again in :seconds seconds.',
|
||||
'throttled' => 'Too many requests. Please try again in :seconds seconds.',
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -217,7 +217,14 @@ class Context
|
||||
public function emailVerification(?string $promptPage = EmailVerificationPrompt::class, bool $isRequired = true): static
|
||||
{
|
||||
$this->emailVerificationPromptPage = $promptPage;
|
||||
$this->isEmailVerificationRequired = $isRequired;
|
||||
$this->requiresEmailVerification($isRequired);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function requiresEmailVerification(bool $condition = true): static
|
||||
{
|
||||
$this->isEmailVerificationRequired = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rules\Password as PasswordRule;
|
||||
use Livewire\Livewire;
|
||||
|
||||
/**
|
||||
* @property Form $form
|
||||
@@ -106,9 +107,6 @@ class ResetPassword extends CardPage
|
||||
->schema([
|
||||
TextInput::make('email')
|
||||
->label(__('filament::pages/auth/password-reset/reset-password.fields.email.label'))
|
||||
->email()
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->disabled(),
|
||||
TextInput::make('password')
|
||||
->label(__('filament::pages/auth/password-reset/reset-password.fields.password.label'))
|
||||
@@ -126,7 +124,7 @@ class ResetPassword extends CardPage
|
||||
|
||||
public function propertyIsPublicAndNotDefinedOnBaseClass($propertyName): bool
|
||||
{
|
||||
if (in_array($propertyName, [
|
||||
if ((! app()->runningUnitTests()) && in_array($propertyName, [
|
||||
'email',
|
||||
'token',
|
||||
])) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class() extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('password_resets', function (Blueprint $table): void {
|
||||
$table->string('email')->index();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('password_resets');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Notifications\Auth\VerifyEmail;
|
||||
use Filament\Pages\Auth\EmailVerification\EmailVerificationPrompt;
|
||||
use Filament\Tests\Models\User;
|
||||
use Filament\Tests\TestCase;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use function Pest\Livewire\livewire;
|
||||
|
||||
uses(TestCase::class);
|
||||
|
||||
it('can render page', function () {
|
||||
$userToVerify = User::factory()->create([
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
|
||||
$this->actingAs($userToVerify);
|
||||
|
||||
$this->get(Filament::getEmailVerificationPromptUrl())->assertSuccessful();
|
||||
});
|
||||
|
||||
it('can resend notification', function () {
|
||||
Notification::fake();
|
||||
|
||||
$userToVerify = User::factory()->create([
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
|
||||
$this->actingAs($userToVerify);
|
||||
|
||||
livewire(EmailVerificationPrompt::class)
|
||||
->call('resendNotification')
|
||||
->assertNotified();
|
||||
|
||||
Notification::assertSentTo($userToVerify, VerifyEmail::class);
|
||||
});
|
||||
|
||||
it('can throttle resend notification attempts', function () {
|
||||
Notification::fake();
|
||||
|
||||
$userToVerify = User::factory()->create([
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
|
||||
$this->actingAs($userToVerify);
|
||||
|
||||
livewire(EmailVerificationPrompt::class)
|
||||
->call('resendNotification')
|
||||
->assertNotified();
|
||||
|
||||
Notification::assertSentToTimes($userToVerify, VerifyEmail::class, times: 1);
|
||||
|
||||
livewire(EmailVerificationPrompt::class)
|
||||
->call('resendNotification')
|
||||
->assertNotified();
|
||||
|
||||
Notification::assertSentToTimes($userToVerify, VerifyEmail::class, times: 1);
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Http\Responses\Auth\Contracts\LogoutResponse;
|
||||
use Filament\Tests\Models\User;
|
||||
use Filament\Tests\TestCase;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
|
||||
uses(TestCase::class);
|
||||
|
||||
it('can verify an email', function () {
|
||||
$userToVerify = User::factory()->create([
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
|
||||
expect($userToVerify)
|
||||
->hasVerifiedEmail()->toBeFalse();
|
||||
|
||||
$this
|
||||
->actingAs($userToVerify)
|
||||
->get(Filament::getVerifyEmailUrl($userToVerify))
|
||||
->assertRedirect(Filament::getUrl());
|
||||
|
||||
expect($userToVerify->refresh())
|
||||
->hasVerifiedEmail()->toBeTrue();
|
||||
});
|
||||
@@ -22,7 +22,7 @@ it('can authenticate', function () {
|
||||
->set('email', $userToAuthenticate->email)
|
||||
->set('password', 'password')
|
||||
->call('authenticate')
|
||||
->assertRedirect(route('filament.admin.pages.dashboard'));
|
||||
->assertRedirect(Filament::getUrl());
|
||||
|
||||
$this->assertAuthenticatedAs($userToAuthenticate);
|
||||
});
|
||||
@@ -82,7 +82,7 @@ it('can throttle authentication attempts', function () {
|
||||
|
||||
it('can validate `email` is required', function () {
|
||||
livewire(Login::class)
|
||||
->assertSet('email', '')
|
||||
->set('email', '')
|
||||
->call('authenticate')
|
||||
->assertHasErrors(['email' => ['required']]);
|
||||
});
|
||||
@@ -96,7 +96,7 @@ it('can validate `email` is valid email', function () {
|
||||
|
||||
it('can validate `password` is required', function () {
|
||||
livewire(Login::class)
|
||||
->assertSet('password', '')
|
||||
->set('password', '')
|
||||
->call('authenticate')
|
||||
->assertHasErrors(['password' => ['required']]);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Notifications\Auth\ResetPassword;
|
||||
use Filament\Pages\Auth\PasswordReset\RequestPasswordReset;
|
||||
use Filament\Tests\Models\User;
|
||||
use Filament\Tests\TestCase;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use function Pest\Livewire\livewire;
|
||||
|
||||
uses(TestCase::class);
|
||||
|
||||
it('can render page', function () {
|
||||
$this->get(Filament::getRequestPasswordResetUrl())->assertSuccessful();
|
||||
});
|
||||
|
||||
it('can request password reset', function () {
|
||||
Notification::fake();
|
||||
|
||||
$this->assertGuest();
|
||||
|
||||
$userToResetPassword = User::factory()->create();
|
||||
|
||||
livewire(RequestPasswordReset::class)
|
||||
->set('email', $userToResetPassword->email)
|
||||
->call('request')
|
||||
->assertNotified();
|
||||
|
||||
Notification::assertSentTo($userToResetPassword, ResetPassword::class);
|
||||
});
|
||||
|
||||
it('can throttle requests', function () {
|
||||
Notification::fake();
|
||||
|
||||
$this->assertGuest();
|
||||
|
||||
$userToResetPassword = User::factory()->create();
|
||||
|
||||
livewire(RequestPasswordReset::class)
|
||||
->set('email', $userToResetPassword->email)
|
||||
->call('request')
|
||||
->assertNotified();
|
||||
|
||||
Notification::assertSentToTimes($userToResetPassword, ResetPassword::class, times: 1);
|
||||
|
||||
livewire(RequestPasswordReset::class)
|
||||
->set('email', $userToResetPassword->email)
|
||||
->call('request')
|
||||
->assertNotified();
|
||||
|
||||
Notification::assertSentToTimes($userToResetPassword, ResetPassword::class, times: 1);
|
||||
});
|
||||
|
||||
it('can validate `email` is required', function () {
|
||||
livewire(RequestPasswordReset::class)
|
||||
->set('email', '')
|
||||
->call('request')
|
||||
->assertHasErrors(['email' => ['required']]);
|
||||
});
|
||||
|
||||
it('can validate `email` is valid email', function () {
|
||||
livewire(RequestPasswordReset::class)
|
||||
->set('email', 'invalid-email')
|
||||
->call('request')
|
||||
->assertHasErrors(['email' => ['email']]);
|
||||
});
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Pages\Auth\PasswordReset\ResetPassword;
|
||||
use Filament\Pages\Auth\Register;
|
||||
use Filament\Tests\Models\User;
|
||||
use Filament\Tests\TestCase;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Str;
|
||||
use function Pest\Livewire\livewire;
|
||||
|
||||
uses(TestCase::class);
|
||||
|
||||
it('can render page', function () {
|
||||
$userToResetPassword = User::factory()->make();
|
||||
$token = Password::createToken($userToResetPassword);
|
||||
|
||||
$this->get(Filament::getResetPasswordUrl(
|
||||
$token,
|
||||
$userToResetPassword,
|
||||
))->assertSuccessful();
|
||||
});
|
||||
|
||||
it('can reset password', function () {
|
||||
Event::fake();
|
||||
|
||||
$this->assertGuest();
|
||||
|
||||
$userToResetPassword = User::factory()->create();
|
||||
$token = Password::createToken($userToResetPassword);
|
||||
|
||||
livewire(ResetPassword::class)
|
||||
->set('email', $userToResetPassword->email)
|
||||
->set('token', $token)
|
||||
->set('password', 'new-password')
|
||||
->set('passwordConfirmation', 'new-password')
|
||||
->call('resetPassword')
|
||||
->assertNotified()
|
||||
->assertRedirect(Filament::getLoginUrl());
|
||||
|
||||
Event::assertDispatched(PasswordReset::class);
|
||||
|
||||
$this->assertCredentials([
|
||||
'email' => $userToResetPassword->email,
|
||||
'password' => 'new-password',
|
||||
]);
|
||||
});
|
||||
|
||||
it('requires request signature', function () {
|
||||
$userToResetPassword = User::factory()->make();
|
||||
$token = Password::createToken($userToResetPassword);
|
||||
|
||||
$this->get(route("filament.admin.auth.password-reset.reset", [
|
||||
'email' => $userToResetPassword->getEmailForPasswordReset(),
|
||||
'token' => $token,
|
||||
]))->assertForbidden();
|
||||
});
|
||||
|
||||
it('requires valid email and token', function () {
|
||||
Event::fake();
|
||||
|
||||
$this->assertGuest();
|
||||
|
||||
$userToResetPassword = User::factory()->create();
|
||||
$token = Password::createToken($userToResetPassword);
|
||||
|
||||
livewire(ResetPassword::class)
|
||||
->set('email', $userToResetPassword->email)
|
||||
->set('token', Str::random())
|
||||
->set('password', 'new-password')
|
||||
->set('passwordConfirmation', 'new-password')
|
||||
->call('resetPassword')
|
||||
->assertNotified()
|
||||
->assertNoRedirect();
|
||||
|
||||
Event::assertNotDispatched(PasswordReset::class);
|
||||
|
||||
livewire(ResetPassword::class)
|
||||
->set('email', fake()->email())
|
||||
->set('token', $token)
|
||||
->set('password', 'new-password')
|
||||
->set('passwordConfirmation', 'new-password')
|
||||
->call('resetPassword')
|
||||
->assertNotified()
|
||||
->assertNoRedirect();
|
||||
|
||||
Event::assertNotDispatched(PasswordReset::class);
|
||||
});
|
||||
|
||||
it('can throttle reset password attempts', function () {
|
||||
Event::fake();
|
||||
|
||||
$this->assertGuest();
|
||||
|
||||
$userToResetPassword = User::factory()->create();
|
||||
$token = Password::createToken($userToResetPassword);
|
||||
|
||||
livewire(ResetPassword::class)
|
||||
->set('email', $userToResetPassword->email)
|
||||
->set('token', $token)
|
||||
->set('password', 'new-password')
|
||||
->set('passwordConfirmation', 'new-password')
|
||||
->call('resetPassword')
|
||||
->assertNotified()
|
||||
->assertRedirect(Filament::getLoginUrl());
|
||||
|
||||
Event::assertDispatchedTimes(PasswordReset::class, times: 1);
|
||||
|
||||
$this->assertCredentials([
|
||||
'email' => $userToResetPassword->email,
|
||||
'password' => 'new-password',
|
||||
]);
|
||||
|
||||
livewire(ResetPassword::class)
|
||||
->set('email', $userToResetPassword->email)
|
||||
->set('token', $token)
|
||||
->set('password', 'newer-password')
|
||||
->set('passwordConfirmation', 'newer-password')
|
||||
->call('resetPassword')
|
||||
->assertNotified()
|
||||
->assertNoRedirect();
|
||||
|
||||
Event::assertDispatchedTimes(PasswordReset::class, times: 1);
|
||||
|
||||
$this->assertCredentials([
|
||||
'email' => $userToResetPassword->email,
|
||||
'password' => 'new-password',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can validate `password` is required', function () {
|
||||
livewire(ResetPassword::class)
|
||||
->set('password', '')
|
||||
->call('resetPassword')
|
||||
->assertHasErrors(['password' => ['required']]);
|
||||
});
|
||||
|
||||
it('can validate `password` is confirmed', function () {
|
||||
livewire(ResetPassword::class)
|
||||
->set('password', Str::random())
|
||||
->set('passwordConfirmation', Str::random())
|
||||
->call('resetPassword')
|
||||
->assertHasErrors(['password' => ['same']]);
|
||||
});
|
||||
|
||||
it('can validate `passwordConfirmation` is required', function () {
|
||||
livewire(ResetPassword::class)
|
||||
->set('passwordConfirmation', '')
|
||||
->call('resetPassword')
|
||||
->assertHasErrors(['passwordConfirmation' => ['required']]);
|
||||
});
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Pages\Auth\Register;
|
||||
use Filament\Tests\Models\User;
|
||||
use Filament\Tests\TestCase;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Str;
|
||||
use function Pest\Livewire\livewire;
|
||||
|
||||
uses(TestCase::class);
|
||||
|
||||
it('can render page', function () {
|
||||
$this->get(Filament::getRegistrationUrl())->assertSuccessful();
|
||||
});
|
||||
|
||||
it('can register', function () {
|
||||
Event::fake();
|
||||
|
||||
$this->assertGuest();
|
||||
|
||||
Filament::getCurrentContext()->requiresEmailVerification(false);
|
||||
|
||||
$userToRegister = User::factory()->make();
|
||||
|
||||
livewire(Register::class)
|
||||
->set('name', $userToRegister->name)
|
||||
->set('email', $userToRegister->email)
|
||||
->set('password', 'password')
|
||||
->set('passwordConfirmation', 'password')
|
||||
->call('register')
|
||||
->assertNotified()
|
||||
->assertRedirect(Filament::getUrl());
|
||||
|
||||
Event::assertDispatched(Registered::class);
|
||||
|
||||
$this->assertAuthenticated();
|
||||
|
||||
$this->assertCredentials([
|
||||
'email' => $userToRegister->email,
|
||||
'password' => 'password',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can register and redirect user to their intended URL', function () {
|
||||
session()->put('url.intended', $intendedUrl = Str::random());
|
||||
|
||||
Filament::getCurrentContext()->requiresEmailVerification(false);
|
||||
|
||||
$userToRegister = User::factory()->make();
|
||||
|
||||
livewire(Register::class)
|
||||
->set('name', $userToRegister->name)
|
||||
->set('email', $userToRegister->email)
|
||||
->set('password', 'password')
|
||||
->set('passwordConfirmation', 'password')
|
||||
->call('register')
|
||||
->assertRedirect($intendedUrl);
|
||||
});
|
||||
|
||||
it('can throttle registration attempts', function () {
|
||||
Event::fake();
|
||||
|
||||
$this->assertGuest();
|
||||
|
||||
$userToRegister = User::factory()->make();
|
||||
|
||||
livewire(Register::class)
|
||||
->set('name', $userToRegister->name)
|
||||
->set('email', $userToRegister->email)
|
||||
->set('password', 'password')
|
||||
->set('passwordConfirmation', 'password')
|
||||
->call('register')
|
||||
->assertNotified();
|
||||
|
||||
Event::assertDispatchedTimes(Registered::class, times: 1);
|
||||
|
||||
$this->assertAuthenticated();
|
||||
|
||||
auth()->logout();
|
||||
|
||||
livewire(Register::class)
|
||||
->set('name', $userToRegister->name)
|
||||
->set('email', $userToRegister->email)
|
||||
->set('password', 'password')
|
||||
->set('passwordConfirmation', 'password')
|
||||
->call('register')
|
||||
->assertNotified();
|
||||
|
||||
Event::assertDispatchedTimes(Registered::class, times: 1);
|
||||
|
||||
$this->assertGuest();
|
||||
});
|
||||
|
||||
it('can validate `name` is required', function () {
|
||||
livewire(Register::class)
|
||||
->set('name', '')
|
||||
->call('register')
|
||||
->assertHasErrors(['name' => ['required']]);
|
||||
});
|
||||
|
||||
it('can validate `name` is max 255 characters', function () {
|
||||
livewire(Register::class)
|
||||
->set('name', Str::random(256))
|
||||
->call('register')
|
||||
->assertHasErrors(['name' => ['max']]);
|
||||
});
|
||||
|
||||
it('can validate `email` is required', function () {
|
||||
livewire(Register::class)
|
||||
->set('email', '')
|
||||
->call('register')
|
||||
->assertHasErrors(['email' => ['required']]);
|
||||
});
|
||||
|
||||
it('can validate `email` is valid email', function () {
|
||||
livewire(Register::class)
|
||||
->set('email', 'invalid-email')
|
||||
->call('register')
|
||||
->assertHasErrors(['email' => ['email']]);
|
||||
});
|
||||
|
||||
it('can validate `email` is max 255 characters', function () {
|
||||
livewire(Register::class)
|
||||
->set('email', Str::random(256))
|
||||
->call('register')
|
||||
->assertHasErrors(['email' => ['max']]);
|
||||
});
|
||||
|
||||
it('can validate `email` is unique', function () {
|
||||
$existingEmail = User::factory()->create()->email;
|
||||
|
||||
livewire(Register::class)
|
||||
->set('email', $existingEmail)
|
||||
->call('register')
|
||||
->assertHasErrors(['email' => ['unique']]);
|
||||
});
|
||||
|
||||
it('can validate `password` is required', function () {
|
||||
livewire(Register::class)
|
||||
->set('password', '')
|
||||
->call('register')
|
||||
->assertHasErrors(['password' => ['required']]);
|
||||
});
|
||||
|
||||
it('can validate `password` is confirmed', function () {
|
||||
livewire(Register::class)
|
||||
->set('password', Str::random())
|
||||
->set('passwordConfirmation', Str::random())
|
||||
->call('register')
|
||||
->assertHasErrors(['password' => ['same']]);
|
||||
});
|
||||
|
||||
it('can validate `passwordConfirmation` is required', function () {
|
||||
livewire(Register::class)
|
||||
->set('passwordConfirmation', '')
|
||||
->call('register')
|
||||
->assertHasErrors(['passwordConfirmation' => ['required']]);
|
||||
});
|
||||
@@ -8,10 +8,12 @@ use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class User extends Authenticatable implements FilamentUser, MustVerifyEmail
|
||||
{
|
||||
use HasFactory;
|
||||
use Notifiable;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user