Skip to content

Commit 74ec0f9

Browse files
committed
chore: cleanup
1 parent c9826db commit 74ec0f9

File tree

13 files changed

+289
-130
lines changed

13 files changed

+289
-130
lines changed

bootstrap/app.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
commands: __DIR__.'/../routes/console.php',
1616
health: '/up',
1717
)
18-
->withMiddleware(function (Middleware $middleware) {
18+
->withMiddleware(function (Middleware $middleware): void {
1919
$middleware->encryptCookies(except: ['appearance', 'sidebar_state']);
2020

2121
$middleware->web(append: [
@@ -24,6 +24,6 @@
2424
AddLinkHeadersForPreloadedAssets::class,
2525
]);
2626
})
27-
->withExceptions(function (Exceptions $exceptions) {
27+
->withExceptions(function (Exceptions $exceptions): void {
2828
//
2929
})->create();

composer.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,7 @@
8888
"test:ci": "vendor/bin/pest --mutate --min=100 --parallel --ci",
8989
"test": [
9090
"@php artisan config:clear --ansi",
91-
"@test:unit"
92-
],
93-
"test:all": [
94-
"@test",
91+
"@test:unit",
9592
"@test:types",
9693
"@test:coverage"
9794
],
@@ -115,7 +112,7 @@
115112
"@lint",
116113
"@fmt:test",
117114
"@refactor:test",
118-
"@test:all",
115+
"@test",
119116
"@typos"
120117
],
121118
"transform": "php artisan typescript:transform --format",

pint.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
{
22
"preset": "laravel",
3+
"notPath": [
4+
"tests/TestCase.php"
5+
],
36
"rules": {
47
"array_push": true,
58
"backtick_to_shell_exec": true,

rector.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
declare(strict_types=1);
44

55
use Rector\Config\RectorConfig;
6+
use Rector\Php83\Rector\ClassMethod\AddOverrideAttributeToOverriddenMethodsRector;
67
use Rector\Privatization\Rector\ClassMethod\PrivatizeFinalClassMethodRector;
78

89
return RectorConfig::configure()
@@ -12,13 +13,21 @@
1213
__DIR__.'/config',
1314
__DIR__.'/database',
1415
__DIR__.'/routes',
16+
__DIR__.'/bootstrap/app.php',
17+
__DIR__.'/public/index.php',
1518
])
16-
->withPhpSets(php84: true)
19+
->withPhpSets()
1720
->withSkip([
21+
AddOverrideAttributeToOverriddenMethodsRector::class,
1822
PrivatizeFinalClassMethodRector::class => [
1923
__DIR__.'/app/Models/*.php',
2024
],
2125
])
22-
->withTypeCoverageLevel(10)
23-
->withDeadCodeLevel(10)
24-
->withCodeQualityLevel(10);
26+
->withPreparedSets(
27+
deadCode: true,
28+
codeQuality: true,
29+
typeDeclarations: true,
30+
privatization: true,
31+
earlyReturn: true,
32+
strictBooleans: true,
33+
);

tests/Feature/Auth/AuthenticationTest.php

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,65 @@
66

77
use App\Models\User;
88

9-
it('can render the login screen', function (): void {
10-
$response = $this->get('/login');
9+
describe('Authentication', function (): void {
10+
it('can render the login screen', function (): void {
11+
$response = $this->get('/login');
1112

12-
$response->assertStatus(200);
13-
});
13+
$response->assertStatus(200);
14+
});
1415

15-
it('can authenticate users using the login screen', function (): void {
16-
$user = User::factory()->create();
16+
it('can authenticate users using the login screen', function (): void {
17+
$user = User::factory()->create();
1718

18-
$response = $this->post('/login', [
19-
'email' => $user->email,
20-
'password' => 'password',
21-
]);
19+
$response = $this->post('/login', [
20+
'email' => $user->email,
21+
'password' => 'password',
22+
]);
2223

23-
$this->assertAuthenticated();
24-
$response->assertRedirect(route('dashboard', absolute: false));
25-
});
24+
$this->assertAuthenticated();
25+
$response->assertRedirect(route('dashboard', absolute: false));
26+
});
2627

27-
it('cannot authenticate users with invalid password', function (): void {
28-
$user = User::factory()->create();
28+
it('cannot authenticate users with invalid password', function (): void {
29+
$user = User::factory()->create();
2930

30-
$this->post('/login', [
31-
'email' => $user->email,
32-
'password' => 'wrong-password',
33-
]);
31+
$this->post('/login', [
32+
'email' => $user->email,
33+
'password' => 'wrong-password',
34+
]);
3435

35-
$this->assertGuest();
36-
});
36+
$this->assertGuest();
37+
});
38+
39+
it('throttles login attempts after too many failed attempts', function (): void {
40+
$user = User::factory()->create();
41+
42+
// Attempt to login with wrong password multiple times to trigger rate limiting
43+
collect(range(1, 5))
44+
->each(fn () => $this->post('/login', [
45+
'email' => $user->email,
46+
'password' => 'wrong-password',
47+
]));
48+
49+
// The next attempt should be throttled
50+
$response = $this->post('/login', [
51+
'email' => $user->email,
52+
'password' => 'wrong-password',
53+
]);
54+
55+
$response->assertSessionHasErrors('email');
56+
$this->assertStringContainsString(
57+
'Too many login attempts',
58+
collect($response->exception->errors())->flatten()->first()
59+
);
60+
});
3761

38-
it('allows users to logout', function (): void {
39-
$user = User::factory()->create();
62+
it('allows users to logout', function (): void {
63+
$user = User::factory()->create();
4064

41-
$response = $this->actingAs($user)->post('/logout');
65+
$response = $this->actingAs($user)->post('/logout');
4266

43-
$this->assertGuest();
44-
$response->assertRedirect('/');
67+
$this->assertGuest();
68+
$response->assertRedirect('/');
69+
});
4570
});

tests/Feature/Auth/EmailVerificationTest.php

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,42 +9,85 @@
99
use Illuminate\Support\Facades\Event;
1010
use Illuminate\Support\Facades\URL;
1111

12-
it('can render the email verification screen', function (): void {
13-
$user = User::factory()->unverified()->create();
12+
describe('Email verification', function (): void {
13+
it('can render the email verification screen', function (): void {
14+
$user = User::factory()->unverified()->create();
1415

15-
$response = $this->actingAs($user)->get('/verify-email');
16+
$response = $this->actingAs($user)->get('/verify-email');
1617

17-
$response->assertStatus(200);
18-
});
18+
$response->assertStatus(200);
19+
});
1920

20-
it('can verify email', function (): void {
21-
$user = User::factory()->unverified()->create();
21+
it('can verify email', function (): void {
22+
$user = User::factory()->unverified()->create();
2223

23-
Event::fake();
24+
Event::fake();
2425

25-
$verificationUrl = URL::temporarySignedRoute(
26-
'verification.verify',
27-
now()->addMinutes(60),
28-
['id' => $user->id, 'hash' => sha1((string) $user->email)]
29-
);
26+
$verificationUrl = URL::temporarySignedRoute(
27+
'verification.verify',
28+
now()->addMinutes(60),
29+
['id' => $user->id, 'hash' => sha1((string) $user->email)]
30+
);
3031

31-
$response = $this->actingAs($user)->get($verificationUrl);
32+
$response = $this->actingAs($user)->get($verificationUrl);
3233

33-
Event::assertDispatched(Verified::class);
34-
$this->assertTrue($user->fresh()->hasVerifiedEmail());
35-
$response->assertRedirect(route('dashboard', absolute: false).'?verified=1');
36-
});
34+
Event::assertDispatched(Verified::class);
35+
$this->assertTrue($user->fresh()->hasVerifiedEmail());
36+
$response->assertRedirect(route('dashboard', absolute: false).'?verified=1');
37+
});
38+
39+
it('does not verify email with invalid hash', function (): void {
40+
$user = User::factory()->unverified()->create();
41+
42+
$verificationUrl = URL::temporarySignedRoute(
43+
'verification.verify',
44+
now()->addMinutes(60),
45+
['id' => $user->id, 'hash' => sha1('wrong-email')]
46+
);
47+
48+
$this->actingAs($user)->get($verificationUrl);
49+
50+
$this->assertFalse($user->fresh()->hasVerifiedEmail());
51+
});
52+
53+
it('can resend verification notification', function (): void {
54+
$user = User::factory()->unverified()->create();
55+
56+
$response = $this->actingAs($user)
57+
->post('/email/verification-notification');
58+
59+
$response->assertSessionHas('status', 'verification-link-sent');
60+
});
61+
62+
it('redirects to dashboard if email already verified when requesting verification notification', function (): void {
63+
$user = User::factory()->create();
64+
65+
$response = $this->actingAs($user)
66+
->post('/email/verification-notification');
67+
68+
$response->assertRedirect(route('dashboard', absolute: false));
69+
});
70+
71+
it('redirects to dashboard if email already verified when visiting verification prompt', function (): void {
72+
$user = User::factory()->create();
73+
74+
$response = $this->actingAs($user)
75+
->get('/verify-email');
76+
77+
$response->assertRedirect(route('dashboard', absolute: false));
78+
});
3779

38-
it('does not verify email with invalid hash', function (): void {
39-
$user = User::factory()->unverified()->create();
80+
it('redirects to dashboard if email already verified when verifying email', function (): void {
81+
$user = User::factory()->create();
4082

41-
$verificationUrl = URL::temporarySignedRoute(
42-
'verification.verify',
43-
now()->addMinutes(60),
44-
['id' => $user->id, 'hash' => sha1('wrong-email')]
45-
);
83+
$verificationUrl = URL::temporarySignedRoute(
84+
'verification.verify',
85+
now()->addMinutes(60),
86+
['id' => $user->id, 'hash' => sha1((string) $user->email)]
87+
);
4688

47-
$this->actingAs($user)->get($verificationUrl);
89+
$response = $this->actingAs($user)->get($verificationUrl);
4890

49-
$this->assertFalse($user->fresh()->hasVerifiedEmail());
91+
$response->assertRedirect(route('dashboard', absolute: false).'?verified=1');
92+
});
5093
});

tests/Feature/Auth/PasswordConfirmationTest.php

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,33 @@
66

77
use App\Models\User;
88

9-
it('can render the confirm password screen', function (): void {
10-
$user = User::factory()->create();
9+
describe('Password confirmation', function (): void {
10+
it('can render the confirm password screen', function (): void {
11+
$user = User::factory()->create();
1112

12-
$response = $this->actingAs($user)->get('/confirm-password');
13+
$response = $this->actingAs($user)->get('/confirm-password');
1314

14-
$response->assertStatus(200);
15-
});
15+
$response->assertStatus(200);
16+
});
1617

17-
it('can confirm password', function (): void {
18-
$user = User::factory()->create();
18+
it('can confirm password', function (): void {
19+
$user = User::factory()->create();
1920

20-
$response = $this->actingAs($user)->post('/confirm-password', [
21-
'password' => 'password',
22-
]);
21+
$response = $this->actingAs($user)->post('/confirm-password', [
22+
'password' => 'password',
23+
]);
2324

24-
$response->assertRedirect();
25-
$response->assertSessionHasNoErrors();
26-
});
25+
$response->assertRedirect();
26+
$response->assertSessionHasNoErrors();
27+
});
2728

28-
it('does not confirm with invalid password', function (): void {
29-
$user = User::factory()->create();
29+
it('does not confirm with invalid password', function (): void {
30+
$user = User::factory()->create();
3031

31-
$response = $this->actingAs($user)->post('/confirm-password', [
32-
'password' => 'wrong-password',
33-
]);
32+
$response = $this->actingAs($user)->post('/confirm-password', [
33+
'password' => 'wrong-password',
34+
]);
3435

35-
$response->assertSessionHasErrors();
36+
$response->assertSessionHasErrors();
37+
});
3638
});

0 commit comments

Comments
 (0)