Files
SealShare/tests/Feature/FileUploadTest.php
T
Andreas Reinhold / reiniandClaude Opus 4.8 d2e8a135c5 Fix upload UI stuck on "Processing files..."
The `uploading` flag was only cleared by `x-init="uploading = false"` on the
file list, which Alpine runs when the element is initialized. Adding a second
batch of files to the same share only patches that existing element, so the
flag stayed true forever: the spinner never went away, the drop zone stayed
disabled and the submit button stayed disabled, making the share impossible
to create.

`updatedFiles()` now dispatches `files-processed`, which runs for every batch,
and the form resets its upload state on that event instead.

Also fixes two adjacent bugs in the drag & drop path: `uploadMultiple()` was
called without callbacks so dropped files showed no progress at all, and
`relativePaths` was replaced instead of appended, shifting every earlier
file's path onto the wrong file on a second drop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 11:44:35 +02:00

159 lines
4.7 KiB
PHP

<?php
use App\Livewire\FileUploader;
use App\Livewire\SystemPasswordPrompt;
use App\Models\Setting;
use App\Models\Share;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Livewire\Livewire;
test('upload page can be rendered', function () {
$response = $this->get(route('upload'));
$response->assertOk();
});
test('upload page requires system password when configured', function () {
Setting::set('system_password', bcrypt('system-secret'));
$response = $this->get(route('upload'));
$response->assertRedirect(route('system-password'));
});
test('upload page accessible after system password verified', function () {
Setting::set('system_password', bcrypt('system-secret'));
$response = $this->withSession(['system_password_verified' => true])
->get(route('upload'));
$response->assertOk();
});
test('file upload creates share', function () {
Storage::fake('shares');
$file = UploadedFile::fake()->create('document.pdf', 1024);
Livewire::test(FileUploader::class)
->set('files', [$file])
->call('createShare')
->assertRedirectContains('/share/');
expect(Share::query()->count())->toBe(1);
$share = Share::query()->first();
expect($share->files)->toHaveCount(1);
expect($share->files->first()->original_name)->toBe('document.pdf');
});
test('file upload with password creates password-protected share', function () {
Storage::fake('shares');
$file = UploadedFile::fake()->create('secret.txt', 512);
Livewire::test(FileUploader::class)
->set('files', [$file])
->set('usePassword', true)
->set('password', 'my-password')
->call('createShare')
->assertRedirectContains('/share/');
$share = Share::query()->first();
expect($share->isPasswordProtected())->toBeTrue();
});
test('file upload with expiration sets expires_at', function () {
Storage::fake('shares');
$file = UploadedFile::fake()->create('file.txt', 256);
Livewire::test(FileUploader::class)
->set('files', [$file])
->set('expiration', '24h')
->call('createShare')
->assertRedirectContains('/share/');
$share = Share::query()->first();
expect($share->expires_at)->not->toBeNull();
});
test('file upload with max downloads sets limit', function () {
Storage::fake('shares');
$file = UploadedFile::fake()->create('file.txt', 256);
Livewire::test(FileUploader::class)
->set('files', [$file])
->set('maxDownloads', 5)
->call('createShare')
->assertRedirectContains('/share/');
$share = Share::query()->first();
expect($share->max_downloads)->toBe(5);
});
test('every upload batch dispatches files-processed to clear the uploading state', function () {
Storage::fake('shares');
Livewire::test(FileUploader::class)
->set('files', [UploadedFile::fake()->create('first.txt', 64)])
->assertDispatched('files-processed')
->set('files', [UploadedFile::fake()->create('second.txt', 64)])
->assertDispatched('files-processed');
});
test('files added in multiple batches end up in the same share', function () {
Storage::fake('shares');
Livewire::test(FileUploader::class)
->set('files', [UploadedFile::fake()->create('first.txt', 64)])
->set('files', [UploadedFile::fake()->create('second.txt', 64)])
->call('createShare')
->assertHasNoErrors()
->assertRedirectContains('/share/');
$share = Share::query()->first();
expect($share->files->pluck('original_name')->all())->toBe(['first.txt', 'second.txt']);
});
test('file upload requires at least one file', function () {
Livewire::test(FileUploader::class)
->set('files', [])
->call('createShare')
->assertHasErrors(['files']);
});
test('file upload blocks when storage is full', function () {
Storage::fake('shares');
Setting::set('max_storage_quota', 100);
Share::factory()->create(['total_size' => 100]);
$file = UploadedFile::fake()->create('file.txt', 1);
Livewire::test(FileUploader::class)
->set('files', [$file])
->call('createShare')
->assertHasErrors(['files']);
});
test('system password prompt verifies correct password', function () {
Setting::set('system_password', bcrypt('system-secret'));
Livewire::test(SystemPasswordPrompt::class)
->set('password', 'system-secret')
->call('verify')
->assertRedirect(route('upload'));
});
test('system password prompt rejects incorrect password', function () {
Setting::set('system_password', bcrypt('system-secret'));
Livewire::test(SystemPasswordPrompt::class)
->set('password', 'wrong')
->call('verify')
->assertHasErrors(['password']);
});