feat: add routes, lang, tests, stubs, docs, and docker configurations
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Permission;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
function makeEditorUser(): User
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$perm = Permission::firstOrCreate(['name' => 'manage global settings', 'guard_name' => 'web']);
|
||||
$user->givePermissionTo($perm);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
Storage::fake('public');
|
||||
});
|
||||
|
||||
// ── Access control ─────────────────────────────────────────────────────────────
|
||||
|
||||
test('guest cannot upload editor images', function () {
|
||||
$this->postJson('/editor/upload')->assertUnauthorized();
|
||||
});
|
||||
|
||||
test('user without manage global settings cannot upload', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->postJson('/editor/upload')
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
// ── Missing file ───────────────────────────────────────────────────────────────
|
||||
|
||||
test('upload without file returns 400', function () {
|
||||
$user = makeEditorUser();
|
||||
|
||||
$this->actingAs($user)
|
||||
->postJson('/editor/upload')
|
||||
->assertStatus(400)
|
||||
->assertJsonPath('error.message', 'No file uploaded.');
|
||||
});
|
||||
|
||||
// ── Type validation ────────────────────────────────────────────────────────────
|
||||
|
||||
test('upload rejects non-image file', function () {
|
||||
$user = makeEditorUser();
|
||||
$file = UploadedFile::fake()->create('shell.php', 100, 'application/x-php');
|
||||
|
||||
$this->actingAs($user)
|
||||
->postJson('/editor/upload', ['upload' => $file])
|
||||
->assertStatus(422);
|
||||
});
|
||||
|
||||
test('upload rejects svg (not in allowed mimes)', function () {
|
||||
$user = makeEditorUser();
|
||||
$file = UploadedFile::fake()->create('vector.svg', 50, 'image/svg+xml');
|
||||
|
||||
$this->actingAs($user)
|
||||
->postJson('/editor/upload', ['upload' => $file])
|
||||
->assertStatus(422);
|
||||
});
|
||||
|
||||
test('upload accepts jpeg image', function () {
|
||||
$user = makeEditorUser();
|
||||
$file = UploadedFile::fake()->image('photo.jpg', 800, 600);
|
||||
|
||||
$this->actingAs($user)
|
||||
->post('/editor/upload', ['upload' => $file])
|
||||
->assertOk()
|
||||
->assertJsonPath('uploaded', 1)
|
||||
->assertJsonStructure(['url', 'fileName']);
|
||||
});
|
||||
|
||||
test('upload accepts png image', function () {
|
||||
$user = makeEditorUser();
|
||||
$file = UploadedFile::fake()->image('icon.png', 100, 100);
|
||||
|
||||
$this->actingAs($user)
|
||||
->post('/editor/upload', ['upload' => $file])
|
||||
->assertOk()
|
||||
->assertJsonPath('uploaded', 1);
|
||||
});
|
||||
|
||||
test('upload accepts webp image', function () {
|
||||
$user = makeEditorUser();
|
||||
$file = UploadedFile::fake()->image('modern.webp', 400, 300);
|
||||
|
||||
$this->actingAs($user)
|
||||
->post('/editor/upload', ['upload' => $file])
|
||||
->assertOk()
|
||||
->assertJsonPath('uploaded', 1);
|
||||
});
|
||||
|
||||
// ── Size limit ─────────────────────────────────────────────────────────────────
|
||||
|
||||
test('upload rejects image exceeding 5 MB', function () {
|
||||
$user = makeEditorUser();
|
||||
$file = UploadedFile::fake()->create('big.jpg', 6000, 'image/jpeg'); // 6 MB
|
||||
|
||||
$this->actingAs($user)
|
||||
->postJson('/editor/upload', ['upload' => $file])
|
||||
->assertStatus(422);
|
||||
});
|
||||
|
||||
// ── Response structure ─────────────────────────────────────────────────────────
|
||||
|
||||
test('successful upload response has uploaded, fileName, url keys', function () {
|
||||
$user = makeEditorUser();
|
||||
$file = UploadedFile::fake()->image('test.jpg');
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->post('/editor/upload', ['upload' => $file])
|
||||
->assertOk()
|
||||
->json();
|
||||
|
||||
expect($response)->toHaveKeys(['uploaded', 'fileName', 'url']);
|
||||
expect($response['uploaded'])->toBe(1);
|
||||
expect($response['url'])->toStartWith('/storage/');
|
||||
});
|
||||
|
||||
// ── File is actually stored ────────────────────────────────────────────────────
|
||||
|
||||
test('uploaded file is persisted to the public disk under editor/', function () {
|
||||
$user = makeEditorUser();
|
||||
$file = UploadedFile::fake()->image('stored.jpg');
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->post('/editor/upload', ['upload' => $file])
|
||||
->json();
|
||||
|
||||
// Strip /storage/ prefix to get the relative path on the public disk
|
||||
$relativePath = substr((string) $response['url'], strlen('/storage/'));
|
||||
Storage::disk('public')->assertExists($relativePath);
|
||||
});
|
||||
Reference in New Issue
Block a user