apiKey = 'test-api-key-'.uniqid(); \DB::table('api_keys')->insert([ 'key' => $this->apiKey, 'description' => 'Test API Key', 'is_active' => true, 'created_at' => now(), 'updated_at' => now(), ]); // Tenant 생성 또는 기존 사용 $this->tenant = Tenant::first() ?? Tenant::withoutEvents(function () { return Tenant::create([ 'company_name' => 'Test Company', 'code' => 'TEST'.uniqid(), 'email' => 'test@example.com', 'phone' => '010-1234-5678', ]); }); // User 생성 $testUserId = 'testuser'.uniqid(); $this->user = User::create([ 'user_id' => $testUserId, 'name' => 'Test User', 'email' => $testUserId.'@example.com', 'password' => bcrypt('password123'), ]); // UserTenant 관계 생성 UserTenant::create([ 'user_id' => $this->user->id, 'tenant_id' => $this->tenant->id, 'is_active' => true, 'is_default' => true, ]); // 로그인 및 토큰 획득 $this->loginAndGetToken(); } protected function loginAndGetToken(): void { $response = $this->withHeaders([ 'X-API-KEY' => $this->apiKey, 'Accept' => 'application/json', ])->postJson('/api/v1/login', [ 'user_id' => $this->user->user_id, 'user_pwd' => 'password123', ]); $response->assertStatus(200); $this->token = $response->json('access_token'); } protected function authenticatedRequest(string $method, string $uri, array $data = []) { return $this->withHeaders([ 'X-API-KEY' => $this->apiKey, 'Authorization' => 'Bearer '.$this->token, 'Accept' => 'application/json', ])->{$method.'Json'}($uri, $data); } // ==================== Popup CRUD Tests ==================== public function test_can_list_popups(): void { Popup::create([ 'tenant_id' => $this->tenant->id, 'title' => 'Test Popup 1', 'content' => 'Test content 1', 'target_type' => 'all', 'status' => 'active', 'started_at' => now()->subDay(), 'ended_at' => now()->addWeek(), 'created_by' => $this->user->id, 'updated_by' => $this->user->id, ]); $response = $this->authenticatedRequest('get', '/api/v1/popups'); $response->assertStatus(200) ->assertJsonStructure([ 'success', 'message', 'data', ]); } public function test_can_create_popup(): void { $response = $this->authenticatedRequest('post', '/api/v1/popups', [ 'title' => 'New Popup', 'content' => '

Welcome!

This is a new popup.

', 'target_type' => 'all', 'status' => 'active', 'started_at' => now()->format('Y-m-d H:i:s'), 'ended_at' => now()->addMonth()->format('Y-m-d H:i:s'), ]); $response->assertStatus(201) ->assertJsonStructure([ 'success', 'message', 'data' => [ 'id', 'title', 'content', 'target_type', 'status', ], ]); $this->assertDatabaseHas('popups', [ 'title' => 'New Popup', 'target_type' => 'all', 'tenant_id' => $this->tenant->id, ]); } public function test_can_show_popup(): void { $popup = Popup::create([ 'tenant_id' => $this->tenant->id, 'title' => 'Show Test Popup', 'content' => 'Show test content', 'target_type' => 'all', 'status' => 'active', 'started_at' => now()->subDay(), 'ended_at' => now()->addWeek(), 'created_by' => $this->user->id, 'updated_by' => $this->user->id, ]); $response = $this->authenticatedRequest('get', "/api/v1/popups/{$popup->id}"); $response->assertStatus(200) ->assertJsonStructure([ 'success', 'message', 'data' => [ 'id', 'title', 'content', ], ]) ->assertJson([ 'data' => [ 'title' => 'Show Test Popup', ], ]); } public function test_can_update_popup(): void { $popup = Popup::create([ 'tenant_id' => $this->tenant->id, 'title' => 'Original Popup', 'content' => 'Original content', 'target_type' => 'all', 'status' => 'active', 'started_at' => now()->subDay(), 'ended_at' => now()->addWeek(), 'created_by' => $this->user->id, 'updated_by' => $this->user->id, ]); $response = $this->authenticatedRequest('put', "/api/v1/popups/{$popup->id}", [ 'title' => 'Updated Popup', 'content' => 'Updated content', 'status' => 'inactive', ]); $response->assertStatus(200); $this->assertDatabaseHas('popups', [ 'id' => $popup->id, 'title' => 'Updated Popup', 'status' => 'inactive', ]); } public function test_can_delete_popup(): void { $popup = Popup::create([ 'tenant_id' => $this->tenant->id, 'title' => 'Delete Test Popup', 'content' => 'Delete test content', 'target_type' => 'all', 'status' => 'active', 'started_at' => now()->subDay(), 'ended_at' => now()->addWeek(), 'created_by' => $this->user->id, 'updated_by' => $this->user->id, ]); $response = $this->authenticatedRequest('delete', "/api/v1/popups/{$popup->id}"); $response->assertStatus(200); $this->assertSoftDeleted('popups', [ 'id' => $popup->id, ]); } // ==================== Active Popups Tests ==================== public function test_can_get_active_popups(): void { // 활성 팝업 (현재 기간 내) Popup::create([ 'tenant_id' => $this->tenant->id, 'title' => 'Active Popup', 'content' => 'Active content', 'target_type' => 'all', 'status' => 'active', 'started_at' => now()->subDay(), 'ended_at' => now()->addWeek(), 'created_by' => $this->user->id, 'updated_by' => $this->user->id, ]); // 비활성 팝업 Popup::create([ 'tenant_id' => $this->tenant->id, 'title' => 'Inactive Popup', 'content' => 'Inactive content', 'target_type' => 'all', 'status' => 'inactive', 'started_at' => now()->subDay(), 'ended_at' => now()->addWeek(), 'created_by' => $this->user->id, 'updated_by' => $this->user->id, ]); // 기간 만료된 팝업 Popup::create([ 'tenant_id' => $this->tenant->id, 'title' => 'Expired Popup', 'content' => 'Expired content', 'target_type' => 'all', 'status' => 'active', 'started_at' => now()->subMonth(), 'ended_at' => now()->subWeek(), 'created_by' => $this->user->id, 'updated_by' => $this->user->id, ]); $response = $this->authenticatedRequest('get', '/api/v1/popups/active'); $response->assertStatus(200); $data = $response->json('data'); $this->assertIsArray($data); // 활성 팝업만 반환되어야 함 $titles = collect($data)->pluck('title')->toArray(); $this->assertContains('Active Popup', $titles); $this->assertNotContains('Inactive Popup', $titles); $this->assertNotContains('Expired Popup', $titles); } public function test_active_popups_respects_date_range(): void { // 아직 시작 안 된 팝업 Popup::create([ 'tenant_id' => $this->tenant->id, 'title' => 'Future Popup', 'content' => 'Future content', 'target_type' => 'all', 'status' => 'active', 'started_at' => now()->addWeek(), 'ended_at' => now()->addMonth(), 'created_by' => $this->user->id, 'updated_by' => $this->user->id, ]); $response = $this->authenticatedRequest('get', '/api/v1/popups/active'); $response->assertStatus(200); $data = $response->json('data'); $titles = collect($data)->pluck('title')->toArray(); $this->assertNotContains('Future Popup', $titles); } // ==================== Target Type Tests ==================== public function test_can_create_popup_with_department_target(): void { // TODO: FormRequest 유효성 검사 규칙에 따라 target_id 검증 필요 // 현재 API는 target_type=department일 때 추가 검증이 있을 수 있음 $this->markTestSkipped('Department target validation rules need to be verified'); $response = $this->authenticatedRequest('post', '/api/v1/popups', [ 'title' => 'Department Popup', 'content' => 'For specific department', 'target_type' => 'department', 'target_id' => 1, 'status' => 'active', 'started_at' => now()->format('Y-m-d H:i:s'), 'ended_at' => now()->addMonth()->format('Y-m-d H:i:s'), ]); $response->assertStatus(201); $this->assertDatabaseHas('popups', [ 'title' => 'Department Popup', 'target_type' => 'department', 'target_id' => 1, ]); } // ==================== Validation Tests ==================== public function test_cannot_create_popup_without_required_fields(): void { $response = $this->authenticatedRequest('post', '/api/v1/popups', [ // title 누락 'content' => 'Some content', ]); $response->assertStatus(422); } public function test_cannot_create_popup_with_invalid_date_range(): void { $response = $this->authenticatedRequest('post', '/api/v1/popups', [ 'title' => 'Invalid Date Popup', 'content' => 'Content', 'target_type' => 'all', 'status' => 'active', 'started_at' => now()->addMonth()->format('Y-m-d H:i:s'), 'ended_at' => now()->format('Y-m-d H:i:s'), // 시작일보다 이전 ]); // 유효성 검사 실패 예상 $response->assertStatus(422); } // ==================== Authentication Tests ==================== public function test_cannot_access_popups_without_authentication(): void { $response = $this->withHeaders([ 'X-API-KEY' => $this->apiKey, 'Accept' => 'application/json', ])->getJson('/api/v1/popups'); $response->assertStatus(401); } }