Update tests

This commit is contained in:
2026-08-04 21:00:01 +02:00
parent 9dcf13a62e
commit 71d679cc5e
18 changed files with 822 additions and 426 deletions
-54
View File
@@ -1,54 +0,0 @@
<?php
namespace Tests\Feature\Auth;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class AuthenticationTest extends TestCase
{
use RefreshDatabase;
public function test_login_screen_can_be_rendered(): void
{
$response = $this->get('/login');
$response->assertStatus(200);
}
public function test_users_can_authenticate_using_the_login_screen(): void
{
$user = User::factory()->create();
$response = $this->post('/login', [
'email' => $user->email,
'password' => 'password',
]);
$this->assertAuthenticated();
$response->assertRedirect(route('dashboard', absolute: false));
}
public function test_users_can_not_authenticate_with_invalid_password(): void
{
$user = User::factory()->create();
$this->post('/login', [
'email' => $user->email,
'password' => 'wrong-password',
]);
$this->assertGuest();
}
public function test_users_can_logout(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)->post('/logout');
$this->assertGuest();
$response->assertRedirect('/');
}
}
@@ -1,58 +0,0 @@
<?php
namespace Tests\Feature\Auth;
use App\Models\User;
use Illuminate\Auth\Events\Verified;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\URL;
use Tests\TestCase;
class EmailVerificationTest extends TestCase
{
use RefreshDatabase;
public function test_email_verification_screen_can_be_rendered(): void
{
$user = User::factory()->unverified()->create();
$response = $this->actingAs($user)->get('/verify-email');
$response->assertStatus(200);
}
public function test_email_can_be_verified(): void
{
$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);
$this->assertTrue($user->fresh()->hasVerifiedEmail());
$response->assertRedirect(route('dashboard', absolute: false).'?verified=1');
}
public function test_email_is_not_verified_with_invalid_hash(): void
{
$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);
$this->assertFalse($user->fresh()->hasVerifiedEmail());
}
}
@@ -1,44 +0,0 @@
<?php
namespace Tests\Feature\Auth;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PasswordConfirmationTest extends TestCase
{
use RefreshDatabase;
public function test_confirm_password_screen_can_be_rendered(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)->get('/confirm-password');
$response->assertStatus(200);
}
public function test_password_can_be_confirmed(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)->post('/confirm-password', [
'password' => 'password',
]);
$response->assertRedirect();
$response->assertSessionHasNoErrors();
}
public function test_password_is_not_confirmed_with_invalid_password(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)->post('/confirm-password', [
'password' => 'wrong-password',
]);
$response->assertSessionHasErrors();
}
}
-73
View File
@@ -1,73 +0,0 @@
<?php
namespace Tests\Feature\Auth;
use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Notification;
use Tests\TestCase;
class PasswordResetTest extends TestCase
{
use RefreshDatabase;
public function test_reset_password_link_screen_can_be_rendered(): void
{
$response = $this->get('/forgot-password');
$response->assertStatus(200);
}
public function test_reset_password_link_can_be_requested(): void
{
Notification::fake();
$user = User::factory()->create();
$this->post('/forgot-password', ['email' => $user->email]);
Notification::assertSentTo($user, ResetPassword::class);
}
public function test_reset_password_screen_can_be_rendered(): void
{
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;
});
}
public function test_password_can_be_reset_with_valid_token(): void
{
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;
});
}
}
-51
View File
@@ -1,51 +0,0 @@
<?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
->assertSessionHasErrorsIn('updatePassword', 'current_password')
->assertRedirect('/profile');
}
}
-31
View File
@@ -1,31 +0,0 @@
<?php
namespace Tests\Feature\Auth;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class RegistrationTest extends TestCase
{
use RefreshDatabase;
public function test_registration_screen_can_be_rendered(): void
{
$response = $this->get('/register');
$response->assertStatus(200);
}
public function test_new_users_can_register(): void
{
$response = $this->post('/register', [
'name' => 'Test User',
'email' => 'test@example.com',
'password' => 'password',
'password_confirmation' => 'password',
]);
$this->assertAuthenticated();
$response->assertRedirect(route('dashboard', absolute: false));
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace Tests\Feature;
use Tests\RefreshDatabase;
use Tests\Support\AltchaPayload;
use Tests\TestCase;
class ContactFormTest extends TestCase
{
use RefreshDatabase;
public function test_contact_requires_fields(): void
{
$this->post('/contact', [])
->assertSessionHasErrors(['name', 'email', 'message', 'subject', 'altcha']);
}
public function test_valid_contact_submission_creates_row(): void
{
$this->post('/contact', [
'name' => 'Jane Doe',
'email' => 'jane@example.com',
'subject' => 'Bug report',
'message' => 'The search page looks broken on mobile.',
'altcha' => AltchaPayload::valid(),
])->assertRedirect();
$this->assertDatabaseHas('contacts', [
'name' => 'Jane Doe',
'email' => 'jane@example.com',
'subject' => 'Bug report',
'message' => 'The search page looks broken on mobile.',
]);
}
}
+1 -1
View File
@@ -7,10 +7,10 @@ use App\Models\Gallery;
use App\Models\Hentai;
use App\Models\Studios;
use App\Services\GalleryService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\RefreshDatabase;
use Tests\TestCase;
class GalleryServiceTest extends TestCase
+60
View File
@@ -0,0 +1,60 @@
<?php
namespace Tests\Feature\Livewire;
use App\Livewire\LikeButton;
use App\Models\Episode;
use App\Models\Hentai;
use App\Models\Studios;
use App\Models\User;
use Livewire\Livewire;
use Maize\Markable\Models\Like;
use Tests\RefreshDatabase;
use Tests\TestCase;
class LikeButtonTest extends TestCase
{
use RefreshDatabase;
private function makeEpisode(): Episode
{
$hentai = Hentai::factory()->create();
$studio = Studios::factory()->create();
return Episode::factory()->create([
'hentai_id' => $hentai->id,
'studios_id' => $studio->id,
]);
}
public function test_guest_like_is_a_noop(): void
{
$episode = $this->makeEpisode();
Livewire::test(LikeButton::class, ['episode' => $episode])
->call('like');
$this->assertDatabaseCount('markable_likes', 0);
}
public function test_user_can_toggle_like(): void
{
$episode = $this->makeEpisode();
$user = User::factory()->create();
$this->actingAs($user);
Livewire::test(LikeButton::class, ['episode' => $episode])
->call('like')
->assertSet('liked', true)
->assertSet('likeCount', 1);
$this->assertTrue(Like::has($episode, $user));
Livewire::test(LikeButton::class, ['episode' => $episode->fresh()])
->call('like')
->assertSet('liked', false)
->assertSet('likeCount', 0);
$this->assertFalse(Like::has($episode, $user));
}
}
@@ -10,26 +10,14 @@ use App\Models\Playlist;
use App\Models\PlaylistEpisode;
use App\Models\Studios;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\RefreshDatabaseState;
use Livewire\Livewire;
use Tests\RefreshDatabase;
use Tests\TestCase;
class PlaylistOverviewTest extends TestCase
{
use RefreshDatabase;
/**
* The repo's post-launch data-fix migrations (e.g. 2026_01_08_213625)
* assume a populated production schema and fail on a fresh database, so
* the "testing" database is provisioned from a production schema dump
* instead of running migrate:fresh.
*/
protected function migrateDatabases(): void
{
RefreshDatabaseState::$migrated = true;
}
private function makePlaylist(int $episodeCount = 1): array
{
$user = User::factory()->create();
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace Tests\Feature;
use App\Models\User;
use Tests\RefreshDatabase;
use Tests\TestCase;
class PlaylistCreationTest extends TestCase
{
use RefreshDatabase;
public function test_authenticated_user_can_create_playlist(): void
{
$user = User::factory()->create();
$this->actingAs($user)
->post('/create-playlist', ['name' => 'My List', 'visiblity' => 'private'])
->assertRedirect(route('profile.playlists'));
$this->assertDatabaseHas('playlists', [
'user_id' => $user->id,
'name' => 'My List',
'is_private' => true,
]);
}
public function test_playlist_requires_a_name(): void
{
$user = User::factory()->create();
$this->actingAs($user)
->post('/create-playlist', [])
->assertSessionHasErrors('name');
}
}
-99
View File
@@ -1,99 +0,0 @@
<?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->assertOk();
}
public function test_profile_information_can_be_updated(): void
{
$user = User::factory()->create();
$response = $this
->actingAs($user)
->patch('/profile', [
'name' => 'Test User',
'email' => 'test@example.com',
]);
$response
->assertSessionHasNoErrors()
->assertRedirect('/profile');
$user->refresh();
$this->assertSame('Test User', $user->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', [
'name' => 'Test User',
'email' => $user->email,
]);
$response
->assertSessionHasNoErrors()
->assertRedirect('/profile');
$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->assertNull($user->fresh());
}
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
->assertSessionHasErrorsIn('userDeletion', 'password')
->assertRedirect('/profile');
$this->assertNotNull($user->fresh());
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
namespace Tests\Feature;
use App\Models\Episode;
use App\Models\Hentai;
use App\Models\Studios;
use Tests\RefreshDatabase;
use Tests\TestCase;
class PublicPagesTest extends TestCase
{
use RefreshDatabase;
public function test_login_page_renders(): void
{
$this->get('/login')->assertOk();
}
public function test_search_page_renders(): void
{
$this->get('/search')->assertOk();
}
public function test_contact_page_renders(): void
{
$this->get('/contact')->assertOk();
}
public function test_guest_is_redirected_to_login(): void
{
$this->get('/user/profile')->assertRedirect(route('login'));
}
public function test_random_redirects_when_episode_exists(): void
{
$hentai = Hentai::factory()->create();
$studio = Studios::factory()->create();
$episode = Episode::factory()->create([
'hentai_id' => $hentai->id,
'studios_id' => $studio->id,
]);
$this->get('/random')->assertRedirect(route('hentai.index', $episode->slug));
}
}
+16
View File
@@ -0,0 +1,16 @@
<?php
namespace Tests\Feature;
use Tests\RefreshDatabase;
use Tests\TestCase;
class StatsPageTest extends TestCase
{
use RefreshDatabase;
public function test_stats_page_renders_with_empty_database(): void
{
$this->get('/stats')->assertOk();
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace Tests;
use Illuminate\Foundation\Testing\RefreshDatabase as BaseRefreshDatabase;
use Illuminate\Support\Facades\DB;
/**
* RefreshDatabase variant that provisions the test database from the committed
* MySQL/MariaDB schema dump (database/schema/mysql-schema.sql) instead of
* running the app's incomplete / data-dependent migrations.
*
* Refresh the dump after schema changes with: php artisan schema:dump
*/
trait RefreshDatabase
{
use BaseRefreshDatabase;
/**
* Import the committed schema dump. It is idempotent: it drops and
* recreates every table, so it also works when the test database already
* exists from a previous run.
*/
protected function migrateDatabases()
{
DB::unprepared(
file_get_contents(database_path('schema/mysql-schema.sql'))
);
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
namespace Tests\Support;
use AltchaOrg\Altcha\Algorithm\Pbkdf2;
use AltchaOrg\Altcha\Altcha;
use AltchaOrg\Altcha\CreateChallengeOptions;
use AltchaOrg\Altcha\SolveChallengeOptions;
/**
* Builds a valid altcha payload for tests using the fixed ALTCHA_HMAC_KEY,
* mirroring the payload shape produced by the browser widget (base64 JSON with
* a challenge array and a solution array).
*/
final class AltchaPayload
{
public static function valid(?int $counter = null): string
{
$pbkdf2 = new Pbkdf2;
$altcha = new Altcha(
hmacSignatureSecret: config('captcha.hmac_key'),
);
$counter ??= random_int(1, 100);
$challenge = $altcha->createChallenge(new CreateChallengeOptions(
algorithm: $pbkdf2,
cost: 5000,
counter: $counter,
expiresAt: time() + 600,
));
$solution = $altcha->solveChallenge(new SolveChallengeOptions(
challenge: $challenge,
algorithm: $pbkdf2,
start: $counter,
step: 1,
timeout: 5,
));
return base64_encode(json_encode([
'challenge' => $challenge->toArray(),
'solution' => $solution->toArray(),
]));
}
}