457 lines
No EOL
13 KiB
PHP
457 lines
No EOL
13 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Foundation\Testing\WithFaker;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Laravel\Sanctum\Sanctum;
|
|
use Tests\TestCase;
|
|
|
|
class AuthTest extends TestCase
|
|
{
|
|
use RefreshDatabase, WithFaker;
|
|
|
|
/**
|
|
* Test user registration with valid data.
|
|
*/
|
|
public function test_user_can_register_with_valid_data()
|
|
{
|
|
$userData = [
|
|
'name' => 'John Doe',
|
|
'email' => 'john@example.com',
|
|
'password' => 'password123',
|
|
'password_confirmation' => 'password123',
|
|
];
|
|
|
|
$response = $this->postJson('/api/register', $userData);
|
|
|
|
$response->assertStatus(201)
|
|
->assertJsonStructure([
|
|
'success',
|
|
'message',
|
|
'data' => [
|
|
'user' => [
|
|
'id',
|
|
'name',
|
|
'email',
|
|
'created_at',
|
|
'updated_at',
|
|
],
|
|
'access_token',
|
|
'token_type',
|
|
]
|
|
])
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'User registered successfully',
|
|
'data' => [
|
|
'user' => [
|
|
'name' => 'John Doe',
|
|
'email' => 'john@example.com',
|
|
],
|
|
'token_type' => 'Bearer',
|
|
]
|
|
]);
|
|
|
|
// Verify user was created in database
|
|
$this->assertDatabaseHas('users', [
|
|
'name' => 'John Doe',
|
|
'email' => 'john@example.com',
|
|
]);
|
|
|
|
// Verify password was hashed
|
|
$user = User::where('email', 'john@example.com')->first();
|
|
$this->assertTrue(Hash::check('password123', $user->password));
|
|
}
|
|
|
|
/**
|
|
* Test registration validation errors.
|
|
*/
|
|
public function test_registration_validates_required_fields()
|
|
{
|
|
// Test without any data
|
|
$response = $this->postJson('/api/register', []);
|
|
|
|
$response->assertStatus(422)
|
|
->assertJson([
|
|
'success' => false,
|
|
'message' => 'Validation errors',
|
|
])
|
|
->assertJsonPath('data.name', fn($value) => !empty($value))
|
|
->assertJsonPath('data.email', fn($value) => !empty($value))
|
|
->assertJsonPath('data.password', fn($value) => !empty($value));
|
|
|
|
// Test with invalid email
|
|
$response = $this->postJson('/api/register', [
|
|
'name' => 'John Doe',
|
|
'email' => 'invalid-email',
|
|
'password' => 'password123',
|
|
'password_confirmation' => 'password123',
|
|
]);
|
|
|
|
$response->assertStatus(422)
|
|
->assertJsonPath('data.email', fn($value) => !empty($value));
|
|
|
|
// Test with password too short
|
|
$response = $this->postJson('/api/register', [
|
|
'name' => 'John Doe',
|
|
'email' => 'john@example.com',
|
|
'password' => '123',
|
|
'password_confirmation' => '123',
|
|
]);
|
|
|
|
$response->assertStatus(422)
|
|
->assertJsonPath('data.password', fn($value) => !empty($value));
|
|
|
|
// Test with password confirmation mismatch
|
|
$response = $this->postJson('/api/register', [
|
|
'name' => 'John Doe',
|
|
'email' => 'john@example.com',
|
|
'password' => 'password123',
|
|
'password_confirmation' => 'different123',
|
|
]);
|
|
|
|
$response->assertStatus(422)
|
|
->assertJsonPath('data.password', fn($value) => !empty($value));
|
|
}
|
|
|
|
/**
|
|
* Test registration with duplicate email.
|
|
*/
|
|
public function test_registration_prevents_duplicate_email()
|
|
{
|
|
// Create an existing user
|
|
User::factory()->create([
|
|
'email' => 'existing@example.com',
|
|
]);
|
|
|
|
$userData = [
|
|
'name' => 'John Doe',
|
|
'email' => 'existing@example.com',
|
|
'password' => 'password123',
|
|
'password_confirmation' => 'password123',
|
|
];
|
|
|
|
$response = $this->postJson('/api/register', $userData);
|
|
|
|
$response->assertStatus(422)
|
|
->assertJsonPath('data.email', fn($value) => !empty($value));
|
|
}
|
|
|
|
/**
|
|
* Test user login with valid credentials.
|
|
*/
|
|
public function test_user_can_login_with_valid_credentials()
|
|
{
|
|
$user = User::factory()->create([
|
|
'email' => 'john@example.com',
|
|
'password' => Hash::make('password123'),
|
|
]);
|
|
|
|
$loginData = [
|
|
'email' => 'john@example.com',
|
|
'password' => 'password123',
|
|
];
|
|
|
|
$response = $this->postJson('/api/login', $loginData);
|
|
|
|
$response->assertStatus(200)
|
|
->assertJsonStructure([
|
|
'success',
|
|
'message',
|
|
'data' => [
|
|
'user' => [
|
|
'id',
|
|
'name',
|
|
'email',
|
|
'created_at',
|
|
'updated_at',
|
|
],
|
|
'access_token',
|
|
'token_type',
|
|
]
|
|
])
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Login successful',
|
|
'data' => [
|
|
'user' => [
|
|
'id' => $user->id,
|
|
'email' => 'john@example.com',
|
|
],
|
|
'token_type' => 'Bearer',
|
|
]
|
|
]);
|
|
|
|
// Verify token is valid
|
|
$this->assertNotEmpty($response->json('data.access_token'));
|
|
}
|
|
|
|
/**
|
|
* Test login with invalid credentials.
|
|
*/
|
|
public function test_login_fails_with_invalid_credentials()
|
|
{
|
|
$user = User::factory()->create([
|
|
'email' => 'john@example.com',
|
|
'password' => Hash::make('correct-password'),
|
|
]);
|
|
|
|
// Test with wrong password - This should return 422 with validation exception
|
|
$response = $this->postJson('/api/login', [
|
|
'email' => 'john@example.com',
|
|
'password' => 'wrong-password',
|
|
]);
|
|
|
|
$response->assertStatus(422);
|
|
|
|
// Test with non-existent email
|
|
$response = $this->postJson('/api/login', [
|
|
'email' => 'nonexistent@example.com',
|
|
'password' => 'password123',
|
|
]);
|
|
|
|
$response->assertStatus(422);
|
|
}
|
|
|
|
/**
|
|
* Test login validation errors.
|
|
*/
|
|
public function test_login_validates_required_fields()
|
|
{
|
|
// Test without any data
|
|
$response = $this->postJson('/api/login', []);
|
|
|
|
$response->assertStatus(422)
|
|
->assertJson([
|
|
'success' => false,
|
|
'message' => 'Validation errors',
|
|
])
|
|
->assertJsonPath('data.email', fn($value) => !empty($value))
|
|
->assertJsonPath('data.password', fn($value) => !empty($value));
|
|
|
|
// Test with invalid email format
|
|
$response = $this->postJson('/api/login', [
|
|
'email' => 'invalid-email',
|
|
'password' => 'password123',
|
|
]);
|
|
|
|
$response->assertStatus(422)
|
|
->assertJsonPath('data.email', fn($value) => !empty($value));
|
|
}
|
|
|
|
/**
|
|
* Test authenticated user can access profile.
|
|
*/
|
|
public function test_authenticated_user_can_access_profile()
|
|
{
|
|
$user = User::factory()->create([
|
|
'name' => 'John Doe',
|
|
'email' => 'john@example.com',
|
|
]);
|
|
|
|
Sanctum::actingAs($user);
|
|
|
|
$response = $this->getJson('/api/profile');
|
|
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Profile retrieved successfully',
|
|
'data' => [
|
|
'id' => $user->id,
|
|
'name' => 'John Doe',
|
|
'email' => 'john@example.com',
|
|
]
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test unauthenticated user cannot access profile.
|
|
*/
|
|
public function test_unauthenticated_user_cannot_access_profile()
|
|
{
|
|
$response = $this->getJson('/api/profile');
|
|
|
|
$response->assertStatus(401);
|
|
}
|
|
|
|
/**
|
|
* Test authenticated user can logout.
|
|
*/
|
|
public function test_authenticated_user_can_logout()
|
|
{
|
|
$user = User::factory()->create();
|
|
$token = $user->createToken('test-token');
|
|
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $token->plainTextToken,
|
|
])->postJson('/api/logout');
|
|
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Logout successful',
|
|
]);
|
|
|
|
// Verify token was deleted
|
|
$this->assertDatabaseMissing('personal_access_tokens', [
|
|
'id' => $token->accessToken->id,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test unauthenticated user cannot logout.
|
|
*/
|
|
public function test_unauthenticated_user_cannot_logout()
|
|
{
|
|
$response = $this->postJson('/api/logout');
|
|
|
|
$response->assertStatus(401);
|
|
}
|
|
|
|
/**
|
|
* Test token authentication works.
|
|
*/
|
|
public function test_token_authentication_works()
|
|
{
|
|
$user = User::factory()->create();
|
|
$token = $user->createToken('test-token');
|
|
|
|
// Test that the token can be used to access protected routes
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $token->plainTextToken,
|
|
])->getJson('/api/user');
|
|
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'id' => $user->id,
|
|
'email' => $user->email,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test invalid token is rejected.
|
|
*/
|
|
public function test_invalid_token_is_rejected()
|
|
{
|
|
$response = $this->withHeaders([
|
|
'Authorization' => 'Bearer invalid-token',
|
|
])->getJson('/api/user');
|
|
|
|
$response->assertStatus(401);
|
|
}
|
|
|
|
/**
|
|
* Test registration creates valid tokens.
|
|
*/
|
|
public function test_registration_creates_valid_token()
|
|
{
|
|
$userData = [
|
|
'name' => 'John Doe',
|
|
'email' => 'john@example.com',
|
|
'password' => 'password123',
|
|
'password_confirmation' => 'password123',
|
|
];
|
|
|
|
$response = $this->postJson('/api/register', $userData);
|
|
$token = $response->json('data.access_token');
|
|
|
|
// Use the token to access a protected route
|
|
$profileResponse = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $token,
|
|
])->getJson('/api/profile');
|
|
|
|
$profileResponse->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'data' => [
|
|
'email' => 'john@example.com',
|
|
]
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test login creates valid tokens.
|
|
*/
|
|
public function test_login_creates_valid_token()
|
|
{
|
|
$user = User::factory()->create([
|
|
'email' => 'john@example.com',
|
|
'password' => Hash::make('password123'),
|
|
]);
|
|
|
|
$loginResponse = $this->postJson('/api/login', [
|
|
'email' => 'john@example.com',
|
|
'password' => 'password123',
|
|
]);
|
|
|
|
$token = $loginResponse->json('data.access_token');
|
|
|
|
// Use the token to access a protected route
|
|
$profileResponse = $this->withHeaders([
|
|
'Authorization' => 'Bearer ' . $token,
|
|
])->getJson('/api/profile');
|
|
|
|
$profileResponse->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'data' => [
|
|
'id' => $user->id,
|
|
]
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Test registration returns user without password.
|
|
*/
|
|
public function test_registration_does_not_return_password()
|
|
{
|
|
$userData = [
|
|
'name' => 'John Doe',
|
|
'email' => 'john@example.com',
|
|
'password' => 'password123',
|
|
'password_confirmation' => 'password123',
|
|
];
|
|
|
|
$response = $this->postJson('/api/register', $userData);
|
|
|
|
$response->assertStatus(201)
|
|
->assertJsonMissing(['data.user.password']);
|
|
}
|
|
|
|
/**
|
|
* Test login returns user without password.
|
|
*/
|
|
public function test_login_does_not_return_password()
|
|
{
|
|
$user = User::factory()->create([
|
|
'email' => 'john@example.com',
|
|
'password' => Hash::make('password123'),
|
|
]);
|
|
|
|
$response = $this->postJson('/api/login', [
|
|
'email' => 'john@example.com',
|
|
'password' => 'password123',
|
|
]);
|
|
|
|
$response->assertStatus(200)
|
|
->assertJsonMissing(['data.user.password']);
|
|
}
|
|
|
|
/**
|
|
* Test profile returns user without password.
|
|
*/
|
|
public function test_profile_does_not_return_password()
|
|
{
|
|
$user = User::factory()->create();
|
|
Sanctum::actingAs($user);
|
|
|
|
$response = $this->getJson('/api/profile');
|
|
|
|
$response->assertStatus(200)
|
|
->assertJsonMissing(['data.password']);
|
|
}
|
|
} |