feat: inisialisasi project kit v2
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
test('login screen can be rendered', function () {
|
||||
$response = $this->get('/login');
|
||||
|
||||
$response->assertStatus(200);
|
||||
});
|
||||
|
||||
test('users can authenticate using the login screen', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->post('/login', [
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertAuthenticated();
|
||||
$response->assertRedirect(route('dashboard', absolute: false));
|
||||
});
|
||||
|
||||
test('users can not authenticate with invalid password', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->post('/login', [
|
||||
'email' => $user->email,
|
||||
'password' => 'wrong-password',
|
||||
]);
|
||||
|
||||
$this->assertGuest();
|
||||
});
|
||||
|
||||
test('users can logout', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->post('/logout');
|
||||
|
||||
$this->assertGuest();
|
||||
$response->assertRedirect('/');
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Events\Verified;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
test('email verification screen can be rendered', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get('/verify-email');
|
||||
|
||||
$response->assertStatus(200);
|
||||
});
|
||||
|
||||
test('email can be verified', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
Event::fake();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1($user->email)]
|
||||
);
|
||||
|
||||
$response = $this->actingAs($user)->get($verificationUrl);
|
||||
|
||||
Event::assertDispatched(Verified::class);
|
||||
expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
|
||||
$response->assertRedirect(route('dashboard', absolute: false).'?verified=1');
|
||||
});
|
||||
|
||||
test('email is not verified with invalid hash', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1('wrong-email')]
|
||||
);
|
||||
|
||||
$this->actingAs($user)->get($verificationUrl);
|
||||
|
||||
expect($user->fresh()->hasVerifiedEmail())->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
test('confirm password screen can be rendered', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get('/confirm-password');
|
||||
|
||||
$response->assertStatus(200);
|
||||
});
|
||||
|
||||
test('password can be confirmed', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->post('/confirm-password', [
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$response->assertRedirect();
|
||||
$response->assertSessionHasNoErrors();
|
||||
});
|
||||
|
||||
test('password is not confirmed with invalid password', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->post('/confirm-password', [
|
||||
'password' => 'wrong-password',
|
||||
]);
|
||||
|
||||
$response->assertSessionHasErrors();
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Notifications\ResetPassword;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
test('reset password link screen can be rendered', function () {
|
||||
$response = $this->get('/forgot-password');
|
||||
|
||||
$response->assertStatus(200);
|
||||
});
|
||||
|
||||
test('reset password link can be requested', function () {
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->post('/forgot-password', ['email' => $user->email]);
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class);
|
||||
});
|
||||
|
||||
test('reset password screen can be rendered', function () {
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->post('/forgot-password', ['email' => $user->email]);
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class, function ($notification) {
|
||||
$response = $this->get('/reset-password/'.$notification->token);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
test('password can be reset with valid token', function () {
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->post('/forgot-password', ['email' => $user->email]);
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) {
|
||||
$response = $this->post('/reset-password', [
|
||||
'token' => $notification->token,
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
'password_confirmation' => 'password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect(route('login'));
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PasswordUpdateTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_password_can_be_updated(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->from('/profile')
|
||||
->put('/password', [
|
||||
'current_password' => 'password',
|
||||
'password' => 'new-password',
|
||||
'password_confirmation' => 'new-password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect('/profile');
|
||||
|
||||
$this->assertTrue(Hash::check('new-password', $user->refresh()->password));
|
||||
}
|
||||
|
||||
public function test_correct_password_must_be_provided_to_update_password(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->from('/profile')
|
||||
->put('/password', [
|
||||
'current_password' => 'wrong-password',
|
||||
'password' => 'new-password',
|
||||
'password_confirmation' => 'new-password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasErrors('current_password')
|
||||
->assertRedirect('/profile');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
test('registration screen can be rendered', function () {
|
||||
$response = $this->get('/register');
|
||||
|
||||
$response->assertStatus(200);
|
||||
});
|
||||
|
||||
test('new users can register', function () {
|
||||
$response = $this->post('/register', [
|
||||
'first_name' => 'Test',
|
||||
'last_name' => 'User',
|
||||
'email' => 'test@example.com',
|
||||
'password' => 'password',
|
||||
'password_confirmation' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertAuthenticated();
|
||||
$response->assertRedirect(route('dashboard', absolute: false));
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
it('redirects to login from root', function () {
|
||||
$response = $this->get('/');
|
||||
|
||||
$response->assertRedirect(route('login'));
|
||||
});
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ProfileTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_profile_page_is_displayed(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->get('/profile');
|
||||
|
||||
$response->assertRedirect(route('settings.index'));
|
||||
}
|
||||
|
||||
public function test_profile_information_can_be_updated(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->patch('/profile', [
|
||||
'first_name' => 'Test',
|
||||
'last_name' => 'User',
|
||||
'email' => 'test@example.com',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect(route('settings.index'));
|
||||
|
||||
$user->refresh();
|
||||
|
||||
$this->assertSame('Test', $user->first_name);
|
||||
$this->assertSame('User', $user->last_name);
|
||||
$this->assertSame('test@example.com', $user->email);
|
||||
$this->assertNull($user->email_verified_at);
|
||||
}
|
||||
|
||||
public function test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->patch('/profile', [
|
||||
'first_name' => 'Test',
|
||||
'last_name' => 'User',
|
||||
'email' => $user->email,
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect(route('settings.index'));
|
||||
|
||||
$this->assertNotNull($user->refresh()->email_verified_at);
|
||||
}
|
||||
|
||||
public function test_user_can_delete_their_account(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->delete('/profile', [
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect('/');
|
||||
|
||||
$this->assertGuest();
|
||||
$this->assertSoftDeleted($user);
|
||||
}
|
||||
|
||||
public function test_correct_password_must_be_provided_to_delete_account(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->from('/profile')
|
||||
->delete('/profile', [
|
||||
'password' => 'wrong-password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasErrors('password')
|
||||
->assertRedirect('/profile');
|
||||
|
||||
$this->assertNotNull($user->fresh());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
beforeEach(function () {
|
||||
Permission::firstOrCreate(['name' => 'user.view', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'user.create', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'user.edit', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'user.delete', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'role.view', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'role.manage', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'settings.manage', 'guard_name' => 'web']);
|
||||
|
||||
$userRole = Role::firstOrCreate(['name' => 'user', 'guard_name' => 'web']);
|
||||
$userRole->syncPermissions(['user.view']);
|
||||
|
||||
$adminRole = Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']);
|
||||
$adminRole->syncPermissions(['user.view', 'user.create', 'user.edit', 'user.delete', 'role.view', 'role.manage']);
|
||||
|
||||
Role::firstOrCreate(['name' => 'super-admin', 'guard_name' => 'web']);
|
||||
});
|
||||
|
||||
it('prevents user role from accessing users list on web', function () {
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole('user');
|
||||
|
||||
$this->actingAs($user)
|
||||
->get('/users')
|
||||
->assertStatus(200);
|
||||
});
|
||||
|
||||
it('prevents user role from deleting users via API', function () {
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole('user');
|
||||
|
||||
$target = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->deleteJson("/api/v1/users/{$target->id}")
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
it('allows admin to create users via API', function () {
|
||||
$admin = User::factory()->create();
|
||||
$admin->assignRole('admin');
|
||||
|
||||
$payload = [
|
||||
'firstName' => 'New',
|
||||
'lastName' => 'User',
|
||||
'email' => 'newuser@example.com',
|
||||
'password' => 'password123',
|
||||
];
|
||||
|
||||
$this->actingAs($admin)
|
||||
->postJson('/api/v1/users', $payload)
|
||||
->assertCreated()
|
||||
->assertJsonPath('data.email', 'newuser@example.com');
|
||||
});
|
||||
|
||||
it('allows admin to update users via API', function () {
|
||||
$admin = User::factory()->create();
|
||||
$admin->assignRole('admin');
|
||||
|
||||
$target = User::factory()->create();
|
||||
|
||||
$this->actingAs($admin)
|
||||
->putJson("/api/v1/users/{$target->id}", ['firstName' => 'Updated'])
|
||||
->assertOk()
|
||||
->assertJsonPath('data.firstName', 'Updated');
|
||||
});
|
||||
|
||||
it('allows super-admin to delete users via API', function () {
|
||||
$superAdmin = User::factory()->create();
|
||||
$superAdmin->assignRole('super-admin');
|
||||
|
||||
$target = User::factory()->create();
|
||||
|
||||
$this->actingAs($superAdmin)
|
||||
->deleteJson("/api/v1/users/{$target->id}")
|
||||
->assertOk();
|
||||
|
||||
expect(User::withTrashed()->find($target->id)->deleted_at)->not->toBeNull();
|
||||
});
|
||||
|
||||
it('prevents user from deleting themselves via web', function () {
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole('super-admin');
|
||||
|
||||
$this->actingAs($user)
|
||||
->delete("/users/{$user->id}")
|
||||
->assertRedirect();
|
||||
|
||||
expect(User::find($user->id))->not->toBeNull();
|
||||
});
|
||||
|
||||
it('correctly returns full name', function () {
|
||||
$user = User::factory()->create([
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe',
|
||||
]);
|
||||
|
||||
expect($user->getFullName())->toBe('John Doe');
|
||||
});
|
||||
|
||||
it('returns user with roles and permissions on API me endpoint', function () {
|
||||
$user = User::factory()->create();
|
||||
$user->assignRole('admin');
|
||||
|
||||
$this->actingAs($user)
|
||||
->getJson('/api/v1/auth/me')
|
||||
->assertOk()
|
||||
->assertJsonStructure(['data' => ['id', 'email', 'roles', 'permissions']]);
|
||||
});
|
||||
Reference in New Issue
Block a user