7a7455e56d
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 15s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Deploy to Production (Local) / Build & Deploy to Production (push) Failing after 1m28s
Build & Package / build (push) Failing after 1m33s
## 변경사항 ### CLAUDE.md - '로컬 개발 & 테스트' 섹션 신규 추가 * SSH 터널링 설정 (Docker 사용 금지) * appsettings.Development.json 설정 * 로컬 서비스 시작 방법 - 배포 전 필수 체크리스트 * Build (0 errors, 0 warnings) * 서비스 시작 확인 * 로그인 테스트 * 모든 Admin 페이지 검증 (200 상태, 500 에러 없음) * E2E 테스트 통과 - 배포 게이트: 로컬 테스트 통과 전 절대 배포 금지 ### E2E 테스트 - complete-admin-flow.spec.ts 신규 추가 * 모든 Admin 페이지 접근 테스트 * 500 에러 감지 * Authorization 검증 ## 교훈 Authorization Policy 500 오류가 로컬에서 먼저 발견되었어야 했음. Docker 없이 SSH 터널로 원격 DB 접속하는 현실을 반영하여 지침화. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
160 lines
5.0 KiB
TypeScript
160 lines
5.0 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('Complete Admin Flow - All Pages', () => {
|
|
const BASE_URL = 'http://localhost:5000';
|
|
const LOGIN_URL = `${BASE_URL}/Account/Login`;
|
|
const ADMIN_DASHBOARD = `${BASE_URL}/Admin/Dashboard`;
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
// 1. 로그인 페이지 접근
|
|
await page.goto(LOGIN_URL);
|
|
await expect(page).toHaveTitle(/Login|로그인/i);
|
|
|
|
// 2. 로그인 시도
|
|
await page.fill('#username', 'admin');
|
|
await page.fill('#password', 'quant123!');
|
|
await page.click('button[type="submit"]');
|
|
|
|
// 3. 로그인 후 리다이렉트 대기
|
|
await page.waitForURL(/Admin|Dashboard/);
|
|
});
|
|
|
|
test('Admin Dashboard 접근 가능', async ({ page }) => {
|
|
console.log('Testing: Admin Dashboard');
|
|
await page.goto(ADMIN_DASHBOARD);
|
|
|
|
// 페이지 로드 확인
|
|
await expect(page).toHaveTitle(/Dashboard|대시보드/i);
|
|
|
|
// 주요 엘리먼트 확인
|
|
const body = await page.content();
|
|
expect(body).toContain('Dashboard');
|
|
|
|
console.log('✓ Dashboard loaded successfully');
|
|
});
|
|
|
|
test('Admin Users 페이지 접근', async ({ page }) => {
|
|
console.log('Testing: Users Page');
|
|
await page.goto(`${BASE_URL}/Admin/Users`);
|
|
|
|
// 페이지 로드 확인
|
|
const statusCode = (await page.goto(`${BASE_URL}/Admin/Users`)).status();
|
|
expect([200, 301, 302]).toContain(statusCode);
|
|
|
|
const content = await page.content();
|
|
expect(content).not.toContain('500');
|
|
expect(content).not.toContain('error');
|
|
|
|
console.log('✓ Users page accessible');
|
|
});
|
|
|
|
test('Admin Collection 페이지 접근', async ({ page }) => {
|
|
console.log('Testing: Collection Page');
|
|
const response = await page.goto(`${BASE_URL}/Admin/Collection`);
|
|
|
|
expect(response?.status()).toBeLessThan(400);
|
|
const content = await page.content();
|
|
expect(content).not.toContain('500');
|
|
|
|
console.log('✓ Collection page accessible');
|
|
});
|
|
|
|
test('Admin Monitoring 페이지 접근', async ({ page }) => {
|
|
console.log('Testing: Monitoring Page');
|
|
const response = await page.goto(`${BASE_URL}/Admin/Monitoring`);
|
|
|
|
expect(response?.status()).toBeLessThan(400);
|
|
const content = await page.content();
|
|
expect(content).not.toContain('500');
|
|
|
|
console.log('✓ Monitoring page accessible');
|
|
});
|
|
|
|
test('Admin Operations 페이지 접근', async ({ page }) => {
|
|
console.log('Testing: Operations Page');
|
|
const response = await page.goto(`${BASE_URL}/Admin/Operations`);
|
|
|
|
expect(response?.status()).toBeLessThan(400);
|
|
const content = await page.content();
|
|
expect(content).not.toContain('500');
|
|
|
|
console.log('✓ Operations page accessible');
|
|
});
|
|
|
|
test('Users Create 페이지 접근', async ({ page }) => {
|
|
console.log('Testing: Users Create Page');
|
|
const response = await page.goto(`${BASE_URL}/Admin/Users/Create`);
|
|
|
|
expect(response?.status()).toBeLessThan(400);
|
|
const content = await page.content();
|
|
expect(content).not.toContain('500');
|
|
expect(content).toContain('Create');
|
|
|
|
console.log('✓ Users Create page accessible');
|
|
});
|
|
|
|
test('모든 Admin 페이지가 200 이상 500 미만 상태코드 반환', async ({ page }) => {
|
|
console.log('Testing: All Admin Pages Status Codes');
|
|
|
|
const adminPages = [
|
|
'/Admin/Dashboard',
|
|
'/Admin/Users',
|
|
'/Admin/Collection',
|
|
'/Admin/Monitoring',
|
|
'/Admin/Operations',
|
|
'/Admin/Users/Create',
|
|
];
|
|
|
|
const results = [];
|
|
|
|
for (const path of adminPages) {
|
|
const fullUrl = `${BASE_URL}${path}`;
|
|
const response = await page.goto(fullUrl);
|
|
const status = response?.status() || 0;
|
|
|
|
results.push({
|
|
path,
|
|
status,
|
|
success: status >= 200 && status < 500,
|
|
});
|
|
|
|
console.log(` ${path} → ${status} ${status >= 200 && status < 500 ? '✓' : '❌'}`);
|
|
|
|
// 각 페이지에서 500 에러가 없는지 확인
|
|
const content = await page.content();
|
|
expect(content).not.toContain('500');
|
|
expect(content).not.toContain('System.InvalidOperationException');
|
|
}
|
|
|
|
// 모든 페이지가 정상인지 확인
|
|
const allSuccess = results.every(r => r.success);
|
|
expect(allSuccess).toBe(true);
|
|
|
|
console.log('\n✅ All Admin pages passed');
|
|
});
|
|
|
|
test('로그아웃 후 보호된 페이지 접근 불가', async ({ page }) => {
|
|
console.log('Testing: Access Control');
|
|
|
|
// 대시보드 접근 가능 확인
|
|
let response = await page.goto(ADMIN_DASHBOARD);
|
|
expect(response?.status()).toBeLessThan(400);
|
|
|
|
// 로그아웃 (쿠키 삭제)
|
|
await page.context().clearCookies();
|
|
|
|
// 보호된 페이지 접근 시도
|
|
response = await page.goto(ADMIN_DASHBOARD);
|
|
|
|
// 로그인 페이지로 리다이렉트되거나 401/403 에러
|
|
const url = page.url();
|
|
expect(
|
|
url.includes('/Account/Login') ||
|
|
url.includes('/Account/AccessDenied') ||
|
|
(response?.status() && [401, 403].includes(response.status()))
|
|
).toBe(true);
|
|
|
|
console.log('✓ Access control working correctly');
|
|
});
|
|
});
|