Files
ladill-transfer/tests/Feature/TransferFilesTest.php
T
isaaccladandCursor 1a95915e21
Deploy Ladill Transfer / deploy (push) Successful in 28s
Separate share transfers from Files storage and add folder upload to New transfer.
Transfers lists only intentional shares while Files shows all storage, and New transfer accepts folder picks with flattened file uploads.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 22:31:45 +00:00

316 lines
10 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Transfer;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Tests\Concerns\FakesTransferBilling;
use Tests\TestCase;
class TransferFilesTest extends TestCase
{
use FakesTransferBilling;
use RefreshDatabase;
private function createUser(): User
{
return User::create([
'public_id' => (string) Str::uuid(),
'name' => 'Test User',
'email' => 'transfer+'.uniqid().'@example.com',
]);
}
private function createShareTransfer(User $user, string $title, string $filename): Transfer
{
$this->actingAs($user)->post(route('transfer.transfers.store'), [
'title' => $title,
'files' => [UploadedFile::fake()->create($filename, 50, 'application/pdf')],
])->assertRedirect();
return Transfer::query()->where('title', $title)->firstOrFail();
}
private function createFolder(User $user, string $name): Transfer
{
$this->actingAs($user)->post(route('transfer.files.folders.store'), [
'name' => $name,
])->assertRedirect();
return Transfer::query()->where('title', $name)->where('is_folder', true)->firstOrFail();
}
public function test_owner_can_download_file(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$transfer = $this->createShareTransfer($user, 'Docs', 'brief.pdf');
$file = $transfer->files()->first();
$this->actingAs($user)
->get(route('transfer.files.download', $file))
->assertOk();
}
public function test_owner_can_delete_file(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$transfer = $this->createShareTransfer($user, 'Docs', 'brief.pdf');
$file = $transfer->files()->first();
$this->actingAs($user)
->delete(route('transfer.files.destroy', $file))
->assertRedirect();
$this->assertDatabaseMissing('transfer_files', ['id' => $file->id]);
}
public function test_owner_can_move_file_into_user_folder(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$this->createShareTransfer($user, 'Loose file', 'one.pdf');
$file = Transfer::query()->where('title', 'Loose file')->first()->files()->first();
$folder = $this->createFolder($user, 'Destination folder');
$this->actingAs($user)
->post(route('transfer.files.move'), [
'destination' => $folder->id,
'files' => [$file->id],
])
->assertRedirect(route('transfer.files.index', ['folder' => $folder->id]));
$this->assertSame($folder->id, $file->fresh()->transfer_id);
}
public function test_files_index_shows_user_folder(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$folder = $this->createFolder($user, 'BKC');
$this->actingAs($user)
->get(route('transfer.files.index'))
->assertOk()
->assertSee('BKC');
$this->actingAs($user)
->get(route('transfer.files.index', ['folder' => $folder->id]))
->assertOk()
->assertSee('BKC');
}
public function test_transfers_index_excludes_files_page_storage(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$folder = $this->createFolder($user, 'Private folder');
$this->actingAs($user)
->postJson(route('transfer.files.upload'), [
'upload_folder_name' => 'Uploaded folder',
'files' => [UploadedFile::fake()->create('secret.txt', 10, 'text/plain')],
])
->assertOk();
$this->actingAs($user)
->post(route('transfer.transfers.store'), [
'title' => 'Shared deck',
'files' => [UploadedFile::fake()->create('deck.pdf', 50, 'application/pdf')],
])
->assertRedirect();
$this->actingAs($user)
->get(route('transfer.transfers.index'))
->assertOk()
->assertSee('Shared deck')
->assertDontSee('Private folder')
->assertDontSee('Uploaded folder');
}
public function test_files_index_shows_root_storage_and_share_files(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$this->actingAs($user)
->post(route('transfer.files.upload'), [
'files' => [UploadedFile::fake()->create('stored.txt', 10, 'text/plain')],
])
->assertRedirect();
$this->actingAs($user)
->post(route('transfer.transfers.store'), [
'title' => 'Shared deck',
'files' => [UploadedFile::fake()->create('deck.pdf', 50, 'application/pdf')],
])
->assertRedirect();
$this->actingAs($user)
->get(route('transfer.files.index'))
->assertOk()
->assertSee('stored.txt')
->assertSee('deck.pdf');
}
public function test_upload_detects_duplicate_filenames(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$this->actingAs($user)->post(route('transfer.files.upload'), [
'files' => [UploadedFile::fake()->create('brief.pdf', 50, 'application/pdf')],
])->assertRedirect();
$this->actingAs($user)
->postJson(route('transfer.files.upload.check'), [
'filenames' => ['brief.pdf', 'new.docx'],
])
->assertOk()
->assertJsonPath('conflicts.0.filename', 'brief.pdf');
}
public function test_upload_can_replace_duplicate_file(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$this->actingAs($user)->post(route('transfer.files.upload'), [
'files' => [UploadedFile::fake()->create('brief.pdf', 50, 'application/pdf')],
])->assertRedirect();
$this->actingAs($user)
->post(route('transfer.files.upload'), [
'files' => [UploadedFile::fake()->create('brief.pdf', 80, 'application/pdf')],
'resolutions' => ['brief.pdf' => 'replace'],
])
->assertRedirect();
$this->assertSame(1, \App\Models\TransferFile::query()->where('original_name', 'brief.pdf')->count());
$this->assertDatabaseHas('transfer_files', ['original_name' => 'brief.pdf']);
}
public function test_upload_keep_both_renames_duplicate(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$this->actingAs($user)->post(route('transfer.files.upload'), [
'files' => [UploadedFile::fake()->create('brief.pdf', 50, 'application/pdf')],
])->assertRedirect();
$this->actingAs($user)
->post(route('transfer.files.upload'), [
'files' => [UploadedFile::fake()->create('brief.pdf', 80, 'application/pdf')],
'resolutions' => ['brief.pdf' => 'keep_both'],
])
->assertRedirect();
$this->assertDatabaseHas('transfer_files', ['original_name' => 'brief.pdf']);
$this->assertDatabaseHas('transfer_files', ['original_name' => 'brief (1).pdf']);
}
public function test_upload_stores_basename_when_folder_path_in_filename(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$this->actingAs($user)
->post(route('transfer.files.upload'), [
'files' => [
UploadedFile::fake()->createWithContent(
'red-logo/icon.svg',
'<svg></svg>',
),
],
])
->assertRedirect();
$this->assertDatabaseHas('transfer_files', ['original_name' => 'icon.svg']);
$this->assertDatabaseMissing('transfer_files', ['original_name' => 'red-logo/icon.svg']);
}
public function test_folder_upload_creates_folder_with_files(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$this->actingAs($user)
->postJson(route('transfer.files.upload'), [
'upload_folder_name' => 'Brand assets',
'files' => [
UploadedFile::fake()->create('logo.svg', 10, 'image/svg+xml'),
UploadedFile::fake()->create('cover.png', 10, 'image/png'),
],
])
->assertOk()
->assertJsonPath('count', 2)
->assertJsonPath('folder_id', fn ($id) => is_int($id));
$folder = Transfer::query()
->where('user_id', $user->id)
->where('is_folder', true)
->where('title', 'Brand assets')
->first();
$this->assertNotNull($folder);
$this->assertSame(2, $folder->files()->count());
$this->assertDatabaseHas('transfer_files', [
'transfer_id' => $folder->id,
'original_name' => 'logo.svg',
]);
$this->assertDatabaseHas('transfer_files', [
'transfer_id' => $folder->id,
'original_name' => 'cover.png',
]);
}
public function test_owner_can_download_folder_as_zip(): void
{
Storage::fake('qr');
$this->fakeTransferBillingApi();
$user = $this->createUser();
$folder = $this->createFolder($user, 'Forum');
$this->actingAs($user)
->postJson(route('transfer.files.upload'), [
'folder' => $folder->id,
'files' => [
UploadedFile::fake()->create('notes.txt', 10, 'text/plain'),
UploadedFile::fake()->create('photo.jpg', 10, 'image/jpeg'),
],
])
->assertOk();
$this->actingAs($user)
->get(route('transfer.files.folders.download', $folder))
->assertOk()
->assertHeader('content-type', 'application/zip');
}
}