feat: integrate PHPStan, Rector and Pint code quality tools (#13)

* feat: integrate PHPStan, Rector and Pint code quality tools

- Add larastan, rector, and rector-laravel dev dependencies
- Configure PHPStan at max level with Larastan extension
- Configure Rector with Laravel sets and code quality rules
- Configure Pint with strict rules (final_class, strict_types)
- Add composer scripts: lint, test:lint, test:types, test:unit
- Add GitHub Actions workflow for CI on push/PR
- Apply code style fixes across all files

* docs: add code quality section to README
This commit is contained in:
Jean-Marc Strauven
2026-01-20 20:58:32 +01:00
committed by GitHub
parent d961b44c30
commit f417ec23c2
45 changed files with 732 additions and 83 deletions

View File

@@ -1,12 +1,14 @@
<?php
declare(strict_types=1);
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
describe('Registration', function () {
it('registers a new user successfully', function () {
describe('Registration', function (): void {
it('registers a new user successfully', function (): void {
$response = $this->postJson('/api/v1/register', [
'name' => 'Test User',
'email' => 'test@example.com',
@@ -33,7 +35,7 @@ describe('Registration', function () {
]);
});
it('fails registration with invalid data', function () {
it('fails registration with invalid data', function (): void {
$response = $this->postJson('/api/v1/register', [
'name' => '',
'email' => 'invalid-email',
@@ -43,7 +45,7 @@ describe('Registration', function () {
$response->assertStatus(422);
});
it('fails registration with duplicate email', function () {
it('fails registration with duplicate email', function (): void {
User::factory()->create(['email' => 'existing@example.com']);
$response = $this->postJson('/api/v1/register', [
@@ -57,8 +59,8 @@ describe('Registration', function () {
});
});
describe('Login', function () {
it('logs in with valid credentials', function () {
describe('Login', function (): void {
it('logs in with valid credentials', function (): void {
$user = User::factory()->create([
'password' => bcrypt('password123'),
]);
@@ -83,7 +85,7 @@ describe('Login', function () {
]);
});
it('fails login with invalid credentials', function () {
it('fails login with invalid credentials', function (): void {
$user = User::factory()->create([
'password' => bcrypt('password123'),
]);
@@ -100,7 +102,7 @@ describe('Login', function () {
]);
});
it('fails login with non-existent user', function () {
it('fails login with non-existent user', function (): void {
$response = $this->postJson('/api/v1/login', [
'email' => 'nonexistent@example.com',
'password' => 'password123',
@@ -110,12 +112,12 @@ describe('Login', function () {
});
});
describe('Logout', function () {
it('logs out authenticated user', function () {
describe('Logout', function (): void {
it('logs out authenticated user', function (): void {
$user = User::factory()->create();
$token = $user->createToken('test-token')->plainTextToken;
$response = $this->withHeader('Authorization', "Bearer {$token}")
$response = $this->withHeader('Authorization', 'Bearer '.$token)
->postJson('/api/v1/logout');
$response->assertStatus(200)
@@ -125,19 +127,19 @@ describe('Logout', function () {
]);
});
it('fails logout without authentication', function () {
it('fails logout without authentication', function (): void {
$response = $this->postJson('/api/v1/logout');
$response->assertStatus(401);
});
});
describe('Me', function () {
it('returns authenticated user data', function () {
describe('Me', function (): void {
it('returns authenticated user data', function (): void {
$user = User::factory()->create();
$token = $user->createToken('test-token')->plainTextToken;
$response = $this->withHeader('Authorization', "Bearer {$token}")
$response = $this->withHeader('Authorization', 'Bearer '.$token)
->getJson('/api/v1/me');
$response->assertStatus(200)
@@ -155,7 +157,7 @@ describe('Me', function () {
]);
});
it('fails without authentication', function () {
it('fails without authentication', function (): void {
$response = $this->getJson('/api/v1/me');
$response->assertStatus(401);

View File

@@ -1,5 +1,9 @@
<?php
declare(strict_types=1);
use Tests\TestCase;
/*
|--------------------------------------------------------------------------
| Test Case
@@ -11,7 +15,7 @@
|
*/
pest()->extend(Tests\TestCase::class)
pest()->extend(TestCase::class)
// ->use(Illuminate\Foundation\Testing\RefreshDatabase::class)
->in('Feature');
@@ -26,9 +30,7 @@ pest()->extend(Tests\TestCase::class)
|
*/
expect()->extend('toBeOne', function () {
return $this->toBe(1);
});
expect()->extend('toBeOne', fn () => $this->toBe(1));
/*
|--------------------------------------------------------------------------
@@ -41,7 +43,7 @@ expect()->extend('toBeOne', function () {
|
*/
function something()
function something(): void
{
// ..
}

View File

@@ -1,10 +1,12 @@
<?php
declare(strict_types=1);
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
class ExampleTest extends TestCase
final class ExampleTest extends TestCase
{
/**
* A basic test example.