Certified/tests/Feature/Certificates/CertificateUploadTest.php
2026-08-09 16:33:53 +02:00

203 lines
6.8 KiB
PHP

<?php
use App\Models\Certificate;
use App\Models\Subscription;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Livewire\Livewire;
beforeEach(function () {
Storage::fake('local');
});
test('the create page is displayed', function () {
$this->actingAs(User::factory()->create());
$this->get(route('certificates.create'))->assertOk();
});
test('a certificate is stored on the private disk', function () {
$user = User::factory()->create();
$this->actingAs($user);
Livewire::test('pages::certificates.create')
->set('file', UploadedFile::fake()->create('cert.pdf', 200, 'application/pdf'))
->set('title', 'My Diploma')
->set('expires_at', now()->addYear()->toDateString())
->call('save')
->assertHasNoErrors()
->assertRedirect(route('certificates.index'));
$certificate = $user->certificates()->firstOrFail();
expect($certificate->title)->toBe('My Diploma')
->and($certificate->file_path)->toStartWith('certificates/'.$user->id.'/');
Storage::disk('local')->assertExists($certificate->file_path);
});
test('certificate details are stored', function () {
$user = User::factory()->create();
$this->actingAs($user);
Livewire::test('pages::certificates.create')
->set('file', UploadedFile::fake()->create('cert.pdf', 200, 'application/pdf'))
->set('title', 'First Aid')
->set('issuer', 'Red Cross')
->set('certificate_number', 'RC-2026-001')
->set('issued_at', '2026-01-10')
->set('expires_at', '2028-01-10')
->set('notes', 'Renewed on-site.')
->call('save')
->assertHasNoErrors();
$certificate = $user->certificates()->firstOrFail();
expect($certificate->issuer)->toBe('Red Cross')
->and($certificate->certificate_number)->toBe('RC-2026-001')
->and($certificate->issued_at->toDateString())->toBe('2026-01-10')
->and($certificate->notes)->toBe('Renewed on-site.');
});
test('the issue date cannot be after the expiry date', function () {
$this->actingAs(User::factory()->create());
Livewire::test('pages::certificates.create')
->set('file', UploadedFile::fake()->create('cert.pdf', 200, 'application/pdf'))
->set('title', 'Bad Dates')
->set('issued_at', '2028-01-10')
->set('expires_at', '2026-01-10')
->call('save')
->assertHasErrors(['issued_at']);
});
test('an invalid file type is rejected', function () {
$this->actingAs(User::factory()->create());
Livewire::test('pages::certificates.create')
->set('file', UploadedFile::fake()->create('malware.exe', 100))
->assertHasErrors(['file']);
});
test('ocr suggestions pre-fill empty fields on upload', function () {
Http::fake([
'custom-ocr.klippa.com/*' => Http::response([
'data' => ['parsed' => [
'document_subject' => 'Scanned Title',
'expiry_date' => '2028-01-15',
]],
]),
]);
$user = User::factory()->create();
Subscription::factory()->for($user)->starter()->create();
$user->ocr_provider = 'klippa';
$user->ocr_api_key = 'key';
$user->save();
$this->actingAs($user);
Livewire::test('pages::certificates.create')
->set('file', UploadedFile::fake()->create('cert.pdf', 200, 'application/pdf'))
->assertSet('title', 'Scanned Title')
->assertSet('expires_at', '2028-01-15');
});
test('ocr is skipped for a free plan user even if an ocr provider is set', function () {
Http::fake([
'custom-ocr.klippa.com/*' => Http::response([
'data' => ['parsed' => ['document_subject' => 'Scanned Title']],
]),
]);
// A free-plan user can end up with a stale ocr_provider (e.g. after a
// downgrade); scanning must stay off regardless of that setting.
$user = User::factory()->create();
$user->ocr_provider = 'klippa';
$user->ocr_api_key = 'key';
$user->save();
$this->actingAs($user);
Livewire::test('pages::certificates.create')
->set('file', UploadedFile::fake()->create('cert.pdf', 200, 'application/pdf'))
->assertSet('title', '');
Http::assertNothingSent();
});
test('ocr does not overwrite fields the user already filled', function () {
Http::fake([
'custom-ocr.klippa.com/*' => Http::response([
'data' => ['parsed' => ['document_subject' => 'Scanned Title']],
]),
]);
$user = User::factory()->create();
Subscription::factory()->for($user)->starter()->create();
$user->ocr_provider = 'klippa';
$user->ocr_api_key = 'key';
$user->save();
$this->actingAs($user);
Livewire::test('pages::certificates.create')
->set('title', 'My Own Title')
->set('file', UploadedFile::fake()->create('cert.pdf', 200, 'application/pdf'))
->assertSet('title', 'My Own Title');
});
test('a free plan user is blocked from adding a certificate past their limit', function () {
$user = User::factory()->create();
Certificate::factory()->for($user)->count(5)->create();
$this->actingAs($user);
$this->get(route('certificates.create'))
->assertOk()
->assertSee('Certificate limit reached');
Livewire::test('pages::certificates.create')
->set('file', UploadedFile::fake()->create('cert.pdf', 200, 'application/pdf'))
->set('title', 'One Too Many')
->set('expires_at', now()->addYear()->toDateString())
->call('save');
expect($user->certificates()->count())->toBe(5);
});
test('a starter plan user is blocked once they reach their higher limit', function () {
$user = User::factory()->create();
Subscription::factory()->for($user)->starter()->create();
Certificate::factory()->for($user)->count(15)->create();
$this->actingAs($user);
Livewire::test('pages::certificates.create')
->set('file', UploadedFile::fake()->create('cert.pdf', 200, 'application/pdf'))
->set('title', 'One Too Many')
->set('expires_at', now()->addYear()->toDateString())
->call('save');
expect($user->certificates()->count())->toBe(15);
});
test('an unlimited plan user is never blocked by the certificate limit', function () {
$user = User::factory()->create();
Subscription::factory()->for($user)->unlimited()->create();
Certificate::factory()->for($user)->count(20)->create();
$this->actingAs($user);
Livewire::test('pages::certificates.create')
->set('file', UploadedFile::fake()->create('cert.pdf', 200, 'application/pdf'))
->set('title', 'Number 21')
->set('expires_at', now()->addYear()->toDateString())
->call('save')
->assertHasNoErrors()
->assertRedirect(route('certificates.index'));
expect($user->certificates()->count())->toBe(21);
});