283 lines
8.6 KiB
PHP
283 lines
8.6 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Document;
|
|
|
|
use App\Http\Middleware\VerifyCsrfToken;
|
|
use App\Models\Document;
|
|
use App\Models\DocumentCategory;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Tests\TestCase;
|
|
use Tests\Traits\SeedsRolesAndPermissions;
|
|
|
|
/**
|
|
* Document Tests
|
|
*
|
|
* Tests document management functionality.
|
|
*/
|
|
class DocumentTest extends TestCase
|
|
{
|
|
use RefreshDatabase, SeedsRolesAndPermissions;
|
|
|
|
protected User $admin;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
Storage::fake('private');
|
|
$this->seedRolesAndPermissions();
|
|
$this->admin = $this->createAdmin();
|
|
}
|
|
|
|
/**
|
|
* Test can view documents list
|
|
*/
|
|
public function test_can_view_documents_list(): void
|
|
{
|
|
$response = $this->actingAs($this->admin)->get(
|
|
route('admin.documents.index')
|
|
);
|
|
|
|
$response->assertStatus(200);
|
|
}
|
|
|
|
/**
|
|
* Test can upload document
|
|
*/
|
|
public function test_can_upload_document(): void
|
|
{
|
|
$category = DocumentCategory::factory()->create();
|
|
$file = UploadedFile::fake()->create('test.pdf', 1024);
|
|
|
|
$response = $this->withoutMiddleware(VerifyCsrfToken::class)
|
|
->actingAs($this->admin)
|
|
->post(route('admin.documents.store'), [
|
|
'title' => '測試文件',
|
|
'description' => '這是測試文件',
|
|
'document_category_id' => $category->id,
|
|
'access_level' => 'admin',
|
|
'file' => $file,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
$this->assertDatabaseHas('documents', ['title' => '測試文件']);
|
|
}
|
|
|
|
/**
|
|
* Test can view document details
|
|
*/
|
|
public function test_can_view_document_details(): void
|
|
{
|
|
$category = DocumentCategory::factory()->create();
|
|
$document = Document::factory()->create([
|
|
'created_by_user_id' => $this->admin->id,
|
|
'document_category_id' => $category->id,
|
|
]);
|
|
|
|
$response = $this->actingAs($this->admin)->get(
|
|
route('admin.documents.show', $document)
|
|
);
|
|
|
|
$response->assertStatus(200);
|
|
}
|
|
|
|
/**
|
|
* Test can update document
|
|
*/
|
|
public function test_can_update_document(): void
|
|
{
|
|
$category = DocumentCategory::factory()->create();
|
|
$document = Document::factory()->create([
|
|
'created_by_user_id' => $this->admin->id,
|
|
'document_category_id' => $category->id,
|
|
'title' => '原始標題',
|
|
'access_level' => 'admin',
|
|
]);
|
|
|
|
$response = $this->withoutMiddleware(VerifyCsrfToken::class)
|
|
->actingAs($this->admin)
|
|
->patch(route('admin.documents.update', $document), [
|
|
'title' => '更新後標題',
|
|
'document_category_id' => $category->id,
|
|
'access_level' => 'admin',
|
|
]);
|
|
|
|
$document->refresh();
|
|
$this->assertEquals('更新後標題', $document->title);
|
|
}
|
|
|
|
/**
|
|
* Test can delete document
|
|
*/
|
|
public function test_can_delete_document(): void
|
|
{
|
|
$category = DocumentCategory::factory()->create();
|
|
$document = Document::factory()->create([
|
|
'created_by_user_id' => $this->admin->id,
|
|
'document_category_id' => $category->id,
|
|
]);
|
|
|
|
$response = $this->withoutMiddleware(VerifyCsrfToken::class)
|
|
->actingAs($this->admin)
|
|
->delete(route('admin.documents.destroy', $document));
|
|
|
|
$response->assertRedirect();
|
|
$this->assertSoftDeleted('documents', ['id' => $document->id]);
|
|
}
|
|
|
|
/**
|
|
* Test document requires title
|
|
*/
|
|
public function test_document_requires_title(): void
|
|
{
|
|
$category = DocumentCategory::factory()->create();
|
|
$file = UploadedFile::fake()->create('test.pdf', 1024);
|
|
|
|
$response = $this->withoutMiddleware(VerifyCsrfToken::class)
|
|
->actingAs($this->admin)
|
|
->post(route('admin.documents.store'), [
|
|
'description' => '這是測試文件',
|
|
'document_category_id' => $category->id,
|
|
'access_level' => 'admin',
|
|
'file' => $file,
|
|
]);
|
|
|
|
$response->assertSessionHasErrors('title');
|
|
}
|
|
|
|
/**
|
|
* Test document requires category
|
|
*/
|
|
public function test_document_requires_category(): void
|
|
{
|
|
$file = UploadedFile::fake()->create('test.pdf', 1024);
|
|
|
|
$response = $this->withoutMiddleware(VerifyCsrfToken::class)
|
|
->actingAs($this->admin)
|
|
->post(route('admin.documents.store'), [
|
|
'title' => '測試文件',
|
|
'description' => '這是測試文件',
|
|
'access_level' => 'admin',
|
|
'file' => $file,
|
|
]);
|
|
|
|
$response->assertSessionHasErrors('document_category_id');
|
|
}
|
|
|
|
/**
|
|
* Test document category filter
|
|
*/
|
|
public function test_document_category_filter(): void
|
|
{
|
|
$category1 = DocumentCategory::factory()->create(['name' => '會議紀錄']);
|
|
$category2 = DocumentCategory::factory()->create(['name' => '財務報表']);
|
|
|
|
Document::factory()->create([
|
|
'created_by_user_id' => $this->admin->id,
|
|
'document_category_id' => $category1->id,
|
|
'title' => '文件A',
|
|
]);
|
|
|
|
Document::factory()->create([
|
|
'created_by_user_id' => $this->admin->id,
|
|
'document_category_id' => $category2->id,
|
|
'title' => '文件B',
|
|
]);
|
|
|
|
$response = $this->actingAs($this->admin)->get(
|
|
route('admin.documents.index', ['category' => $category1->id])
|
|
);
|
|
|
|
$response->assertStatus(200);
|
|
$response->assertSee('文件A');
|
|
}
|
|
|
|
/**
|
|
* Test document search
|
|
*/
|
|
public function test_document_search(): void
|
|
{
|
|
$category = DocumentCategory::factory()->create();
|
|
Document::factory()->create([
|
|
'created_by_user_id' => $this->admin->id,
|
|
'document_category_id' => $category->id,
|
|
'title' => '重要會議紀錄',
|
|
]);
|
|
|
|
$response = $this->actingAs($this->admin)->get(
|
|
route('admin.documents.index', ['search' => '重要會議'])
|
|
);
|
|
|
|
$response->assertStatus(200);
|
|
$response->assertSee('重要會議紀錄');
|
|
}
|
|
|
|
/**
|
|
* Test document version upload
|
|
*/
|
|
public function test_document_version_upload(): void
|
|
{
|
|
$category = DocumentCategory::factory()->create();
|
|
$document = Document::factory()->create([
|
|
'created_by_user_id' => $this->admin->id,
|
|
'document_category_id' => $category->id,
|
|
'version_count' => 1,
|
|
]);
|
|
|
|
// Upload new version
|
|
$file = UploadedFile::fake()->create('test_v2.pdf', 1024);
|
|
|
|
$response = $this->withoutMiddleware(VerifyCsrfToken::class)
|
|
->actingAs($this->admin)
|
|
->post(route('admin.documents.upload-version', $document), [
|
|
'file' => $file,
|
|
'version_notes' => '更新版本說明',
|
|
]);
|
|
|
|
$document->refresh();
|
|
$this->assertEquals(2, $document->version_count);
|
|
}
|
|
|
|
/**
|
|
* Test public download returns UTF-8 compatible content disposition
|
|
*/
|
|
public function test_public_document_download_uses_utf8_content_disposition(): void
|
|
{
|
|
$category = DocumentCategory::factory()->create();
|
|
$document = Document::factory()->create([
|
|
'created_by_user_id' => $this->admin->id,
|
|
'document_category_id' => $category->id,
|
|
'access_level' => 'public',
|
|
'status' => 'active',
|
|
'version_count' => 0,
|
|
]);
|
|
|
|
$filePath = 'documents/charter-v2.pdf';
|
|
Storage::disk('private')->put($filePath, 'pdf-content');
|
|
Storage::put($filePath, 'pdf-content');
|
|
|
|
$document->addVersion(
|
|
filePath: $filePath,
|
|
originalFilename: '台灣尤塞氏症暨視聽弱協會章程V2.pdf',
|
|
mimeType: 'application/pdf',
|
|
fileSize: Storage::disk('private')->size($filePath),
|
|
uploadedBy: $this->admin,
|
|
versionNotes: '初始版本'
|
|
);
|
|
|
|
$response = $this->get(route('documents.public.download', [
|
|
'uuid' => $document->public_uuid,
|
|
]));
|
|
|
|
$response->assertOk();
|
|
|
|
$disposition = (string) $response->headers->get('Content-Disposition');
|
|
$this->assertStringContainsString(
|
|
"filename*=UTF-8''".rawurlencode('台灣尤塞氏症暨視聽弱協會章程V2.pdf'),
|
|
$disposition
|
|
);
|
|
}
|
|
}
|