Files
Gnuboard7/tests/Unit/Extension/BuildCommandBundledTest.php
2026-04-01 10:30:52 +09:00

347 lines
12 KiB
PHP

<?php
namespace Tests\Unit\Extension;
use App\Extension\AbstractModule;
use App\Extension\AbstractPlugin;
use App\Extension\ModuleManager;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\File;
use Tests\TestCase;
/**
* 확장 빌드 커맨드 _bundled 기준 전환 테스트
*
* canBuild() 메서드와 빌드 커맨드의 경로 결정 로직을 검증합니다.
*/
class BuildCommandBundledTest extends TestCase
{
use RefreshDatabase;
// ========================================================================
// canBuild() 메서드 테스트
// ========================================================================
/**
* canBuild()이 JS 엔트리포인트가 있으면 true를 반환하는지 테스트
*/
public function test_module_can_build_returns_true_with_js_entry(): void
{
$module = $this->createModuleWithAssets([
'js' => ['entry' => 'resources/js/index.ts', 'output' => 'dist/js/module.iife.js'],
]);
$this->assertTrue($module->canBuild());
}
/**
* canBuild()이 CSS 엔트리포인트가 있으면 true를 반환하는지 테스트
*/
public function test_module_can_build_returns_true_with_css_entry(): void
{
$module = $this->createModuleWithAssets([
'css' => ['entry' => 'resources/css/main.css', 'output' => 'dist/css/module.css'],
]);
$this->assertTrue($module->canBuild());
}
/**
* canBuild()이 엔트리포인트 없으면 false를 반환하는지 테스트
*/
public function test_module_can_build_returns_false_without_entry(): void
{
$module = $this->createModuleWithAssets([
'js' => ['output' => 'dist/js/module.iife.js'],
]);
$this->assertFalse($module->canBuild());
}
/**
* canBuild()이 에셋 섹션 자체가 없으면 false를 반환하는지 테스트
*/
public function test_module_can_build_returns_false_without_assets(): void
{
$module = $this->createModuleWithAssets([]);
$this->assertFalse($module->canBuild());
}
/**
* 플러그인 canBuild()이 JS 엔트리포인트가 있으면 true를 반환하는지 테스트
*/
public function test_plugin_can_build_returns_true_with_js_entry(): void
{
$plugin = $this->createPluginWithAssets([
'js' => ['entry' => 'resources/js/index.ts', 'output' => 'dist/js/plugin.iife.js'],
]);
$this->assertTrue($plugin->canBuild());
}
/**
* 플러그인 canBuild()이 엔트리포인트 없으면 false를 반환하는지 테스트
*/
public function test_plugin_can_build_returns_false_without_entry(): void
{
$plugin = $this->createPluginWithAssets([]);
$this->assertFalse($plugin->canBuild());
}
// ========================================================================
// 빌드 커맨드 시그니처 테스트
// ========================================================================
/**
* module:build 커맨드에 --active 옵션이 있는지 테스트
*/
public function test_module_build_has_active_option(): void
{
$this->artisan('module:build', ['identifier' => 'nonexistent-module'])
->assertFailed();
}
/**
* module:build 인자 없이 실행 시 사용법이 출력되고 --active 옵션이 안내되는지 테스트
*/
public function test_module_build_without_args_shows_active_option_usage(): void
{
$this->artisan('module:build')
->expectsOutputToContain('--active')
->assertFailed();
}
/**
* template:build 인자 없이 실행 시 사용법이 출력되고 --active 옵션이 안내되는지 테스트
*/
public function test_template_build_without_args_shows_active_option_usage(): void
{
$this->artisan('template:build')
->expectsOutputToContain('--active')
->assertFailed();
}
/**
* plugin:build 인자 없이 실행 시 사용법이 출력되고 --active 옵션이 안내되는지 테스트
*/
public function test_plugin_build_without_args_shows_active_option_usage(): void
{
$this->artisan('plugin:build')
->expectsOutputToContain('--active')
->assertFailed();
}
// ========================================================================
// 빌드 경로 결정 로직 테스트 (resolveBuildPath)
// ========================================================================
/**
* _bundled에만 존재하는 모듈은 _bundled 경로가 선택되는지 테스트
*/
public function test_module_build_resolves_bundled_path_when_only_bundled_exists(): void
{
$identifier = 'test-buildpath-bundled-'.uniqid();
$bundledPath = base_path("modules/_bundled/{$identifier}");
$activePath = base_path("modules/{$identifier}");
try {
// _bundled에만 디렉토리와 package.json 생성
File::ensureDirectoryExists($bundledPath);
File::put($bundledPath.'/package.json', json_encode(['name' => $identifier]));
File::put($bundledPath.'/module.json', json_encode([
'identifier' => $identifier,
'name' => ['ko' => '테스트'],
'version' => '1.0.0',
]));
// 모듈 로드
$moduleManager = app(ModuleManager::class);
$moduleManager->loadModules();
// 빌드 실행 → _bundled 경로가 선택되어야 함
$this->artisan('module:build', ['identifier' => $identifier])
->expectsOutputToContain('_bundled')
->assertFailed(); // npm build는 실패하지만 경로 선택은 확인 가능
} finally {
// 정리
if (File::isDirectory($bundledPath)) {
File::deleteDirectory($bundledPath);
}
if (File::isDirectory($activePath)) {
File::deleteDirectory($activePath);
}
}
}
/**
* --active 옵션 사용 시 활성 디렉토리가 선택되는지 테스트
*/
public function test_module_build_resolves_active_path_with_active_option(): void
{
$identifier = 'test-buildpath-active-'.uniqid();
$bundledPath = base_path("modules/_bundled/{$identifier}");
$activePath = base_path("modules/{$identifier}");
try {
// 양쪽 모두 존재하는 상황
File::ensureDirectoryExists($bundledPath);
File::put($bundledPath.'/package.json', json_encode(['name' => $identifier]));
File::put($bundledPath.'/module.json', json_encode([
'identifier' => $identifier,
'name' => ['ko' => '테스트'],
'version' => '1.0.0',
]));
File::ensureDirectoryExists($activePath);
File::put($activePath.'/package.json', json_encode(['name' => $identifier]));
File::put($activePath.'/module.json', json_encode([
'identifier' => $identifier,
'name' => ['ko' => '테스트'],
'version' => '1.0.0',
]));
// 모듈 로드
$moduleManager = app(ModuleManager::class);
$moduleManager->loadModules();
// --active 옵션으로 실행 → 활성 경로가 선택되어야 함
$this->artisan('module:build', [
'identifier' => $identifier,
'--active' => true,
])
->expectsOutputToContain('활성')
->assertFailed(); // npm build는 실패하지만 경로 선택은 확인 가능
} finally {
if (File::isDirectory($bundledPath)) {
File::deleteDirectory($bundledPath);
}
if (File::isDirectory($activePath)) {
File::deleteDirectory($activePath);
}
}
}
/**
* 존재하지 않는 모듈 빌드 시 적절한 오류 메시지가 출력되는지 테스트
*/
public function test_module_build_fails_when_module_not_found(): void
{
$this->artisan('module:build', ['identifier' => 'nonexistent-module-'.uniqid()])
->expectsOutputToContain('찾을 수 없습니다')
->assertFailed();
}
/**
* 존재하지 않는 플러그인 빌드 시 적절한 오류 메시지가 출력되는지 테스트
*/
public function test_plugin_build_fails_when_plugin_not_found(): void
{
$this->artisan('plugin:build', ['identifier' => 'nonexistent-plugin-'.uniqid()])
->expectsOutputToContain('찾을 수 없습니다')
->assertFailed();
}
/**
* 존재하지 않는 템플릿 빌드 시 적절한 오류 메시지가 출력되는지 테스트
*/
public function test_template_build_fails_when_template_not_found(): void
{
$this->artisan('template:build', ['identifier' => 'nonexistent-template-'.uniqid()])
->expectsOutputToContain('찾을 수 없습니다')
->assertFailed();
}
/**
* --active 옵션으로 활성 디렉토리가 없는 모듈 빌드 시 실패하는지 테스트
*/
public function test_module_build_with_active_fails_when_no_active_dir(): void
{
$this->artisan('module:build', [
'identifier' => 'nonexistent-active-'.uniqid(),
'--active' => true,
])
->expectsOutputToContain('찾을 수 없습니다')
->assertFailed();
}
// ========================================================================
// 헬퍼 메서드
// ========================================================================
/**
* 지정된 에셋 설정으로 테스트용 AbstractModule 인스턴스를 생성합니다.
*
* @param array $assets 에셋 설정 배열
* @return AbstractModule 테스트용 모듈 인스턴스
*/
private function createModuleWithAssets(array $assets): AbstractModule
{
return new class($assets) extends AbstractModule
{
public function __construct(private array $testAssets)
{
// 부모 생성자 호출하지 않음 (테스트용)
}
public function getName(): array
{
return ['ko' => '테스트', 'en' => 'Test'];
}
public function getVersion(): string
{
return '1.0.0';
}
public function getDescription(): array
{
return ['ko' => '테스트', 'en' => 'Test'];
}
public function getAssets(): array
{
return $this->testAssets;
}
};
}
/**
* 지정된 에셋 설정으로 테스트용 AbstractPlugin 인스턴스를 생성합니다.
*
* @param array $assets 에셋 설정 배열
* @return AbstractPlugin 테스트용 플러그인 인스턴스
*/
private function createPluginWithAssets(array $assets): AbstractPlugin
{
return new class($assets) extends AbstractPlugin
{
public function __construct(private array $testAssets)
{
// 부모 생성자 호출하지 않음 (테스트용)
}
public function getName(): array
{
return ['ko' => '테스트', 'en' => 'Test'];
}
public function getVersion(): string
{
return '1.0.0';
}
public function getDescription(): array
{
return ['ko' => '테스트', 'en' => 'Test'];
}
public function getAssets(): array
{
return $this->testAssets;
}
};
}
}