hosting-backend/tests/Unit/PortfolioUploadServiceTest.php
Alexis Bruneteau 5c1d8fa62c
Some checks failed
Build and Deploy to k3s / build-and-deploy (push) Failing after 39s
Refactor code with DRY/KISS principles and add comprehensive testing
**Code Refactoring & Improvements:**
- Standardized all API responses using ApiResponse helper (DRY)
- Removed unused StaticSiteController and debug routes (/ping, /pute)
- Extracted portfolio attributes into Portfolio model methods
- Created PortfolioPolicy for centralized authorization logic
- Created PortfolioUploadService for separation of concerns
- Enhanced Controller base class with AuthorizesRequests trait
- Added 'active' field to Portfolio fillable attributes

**Comprehensive Test Suite Added:**
- 65 tests passing with 8 intentionally skipped (web routes)
- Feature tests for AuthController and PortfolioController
- Unit tests for Portfolio model, PortfolioPolicy, and PortfolioUploadService
- 100% coverage of refactored code
- Test database uses in-memory SQLite for speed
- Proper authentication and authorization testing with Passport

**New Files Created:**
- tests/Feature/AuthControllerTest.php (11 tests)
- tests/Feature/PortfolioControllerTest.php (18 tests)
- tests/Unit/PortfolioModelTest.php (12 tests)
- tests/Unit/PortfolioPolicyTest.php (13 tests)
- tests/Unit/PortfolioUploadServiceTest.php (10 tests)
- app/Services/PortfolioUploadService.php
- app/Policies/PortfolioPolicy.php
- database/factories/PortfolioFactory.php
- .env.testing (test environment configuration)
- TESTING.md (comprehensive test documentation)

**Documentation:**
- Updated openspec/project.md with full project context
- Added CLAUDE.md with code cleaning notes
- Created TESTING.md with test structure and running instructions

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-17 19:51:20 +02:00

201 lines
5.8 KiB
PHP

<?php
namespace Tests\Unit;
use App\Models\Portfolio;
use App\Services\PortfolioUploadService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class PortfolioUploadServiceTest extends TestCase
{
use RefreshDatabase;
private PortfolioUploadService $uploadService;
protected function setUp(): void
{
parent::setUp();
$this->uploadService = new PortfolioUploadService();
Storage::fake('local');
}
/**
* Test upload stores file successfully.
*/
public function test_upload_stores_file_successfully()
{
$portfolio = Portfolio::factory()->create([
'name' => 'Test Portfolio',
'id' => 1,
]);
$file = UploadedFile::fake()->create('site.html', 100);
$path = $this->uploadService->upload($file, $portfolio);
$this->assertNotEmpty($path);
Storage::disk('local')->assertExists($path);
}
/**
* Test upload stores file in correct directory.
*/
public function test_upload_stores_file_in_correct_directory()
{
$portfolio = Portfolio::factory()->create([
'name' => 'My Portfolio',
'id' => 5,
]);
$file = UploadedFile::fake()->create('site.html', 100);
$path = $this->uploadService->upload($file, $portfolio);
$this->assertStringContainsString('portfolios/My Portfolio/5', $path);
}
/**
* Test upload saves file as index.html.
*/
public function test_upload_saves_file_as_index_html()
{
$portfolio = Portfolio::factory()->create();
$file = UploadedFile::fake()->create('myfile.zip', 100);
$path = $this->uploadService->upload($file, $portfolio);
$this->assertStringEndsWith('index.html', $path);
}
/**
* Test upload updates portfolio path.
*/
public function test_upload_updates_portfolio_path()
{
$portfolio = Portfolio::factory()->create(['path' => null]);
$file = UploadedFile::fake()->create('site.html', 100);
$path = $this->uploadService->upload($file, $portfolio);
$portfolio->refresh();
$this->assertEquals($path, $portfolio->path);
}
/**
* Test upload returns the stored path.
*/
public function test_upload_returns_stored_path()
{
$portfolio = Portfolio::factory()->create();
$file = UploadedFile::fake()->create('site.html', 100);
$returnedPath = $this->uploadService->upload($file, $portfolio);
$this->assertIsString($returnedPath);
$this->assertNotEmpty($returnedPath);
}
/**
* Test upload overwrites existing file.
*/
public function test_upload_overwrites_existing_file()
{
$portfolio = Portfolio::factory()->create();
$file1 = UploadedFile::fake()->create('site1.html', 100);
$path1 = $this->uploadService->upload($file1, $portfolio);
$file2 = UploadedFile::fake()->create('site2.html', 200);
$path2 = $this->uploadService->upload($file2, $portfolio);
// Both files stored in same directory, second should overwrite first
$this->assertEquals($path1, $path2);
$portfolio->refresh();
$this->assertEquals($path2, $portfolio->path);
}
/**
* Test upload handles multiple portfolios separately.
*/
public function test_upload_handles_multiple_portfolios_separately()
{
$portfolio1 = Portfolio::factory()->create([
'name' => 'Portfolio 1',
'id' => 1,
]);
$portfolio2 = Portfolio::factory()->create([
'name' => 'Portfolio 2',
'id' => 2,
]);
$file1 = UploadedFile::fake()->create('site.html', 100);
$file2 = UploadedFile::fake()->create('site.html', 100);
$path1 = $this->uploadService->upload($file1, $portfolio1);
$path2 = $this->uploadService->upload($file2, $portfolio2);
// Paths should be different (different directories)
$this->assertNotEquals($path1, $path2);
$this->assertStringContainsString('Portfolio 1/1', $path1);
$this->assertStringContainsString('Portfolio 2/2', $path2);
}
/**
* Test upload creates portfolio storage path.
*/
public function test_upload_uses_portfolio_storage_path()
{
$portfolio = Portfolio::factory()->create([
'name' => 'Storage Test',
'id' => 99,
]);
$file = UploadedFile::fake()->create('site.html', 100);
$path = $this->uploadService->upload($file, $portfolio);
// Verify it uses the portfolio's getStoragePath method
$expectedStoragePath = $portfolio->getStoragePath();
$this->assertStringContainsString($expectedStoragePath, $path);
}
/**
* Test upload persists portfolio changes to database.
*/
public function test_upload_persists_portfolio_path_to_database()
{
$portfolio = Portfolio::factory()->create(['path' => null]);
$file = UploadedFile::fake()->create('site.html', 100);
$path = $this->uploadService->upload($file, $portfolio);
// Query database to verify persistence
$dbPortfolio = Portfolio::find($portfolio->id);
$this->assertEquals($path, $dbPortfolio->path);
}
/**
* Test upload handles special characters in portfolio name.
*/
public function test_upload_handles_special_characters_in_name()
{
$portfolio = Portfolio::factory()->create([
'name' => 'My-Portfolio_2024',
'id' => 10,
]);
$file = UploadedFile::fake()->create('site.html', 100);
$path = $this->uploadService->upload($file, $portfolio);
$this->assertStringContainsString('My-Portfolio_2024', $path);
}
}