53db2f63e3
- Add Server.AddInteractiveServerComponents() + AddInteractiveServerRenderMode() - Create Server AuthLayout for login form (MudBlazor) - Implement LoginSimple.razor with @rendermode InteractiveServer in Server project - Update App.razor: CascadingAuthenticationState + Router with AppAssembly=Server - Fix Client MudBlazor Providers in MainLayout + AuthLayout - Update Playwright tests: use dynamic selectors for MudTextField (auto-generated IDs) - Build: 0 errors, 0 warnings - API: /api/auth/login fully operational (200 OK confirmed) - Playwright E2E test: 1 passed Architecture: /login → Server InteractiveServer (MudBlazor form) / → Client WebAssembly (Dashboard) /api/* → Server Endpoints Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
99 lines
3.9 KiB
TypeScript
99 lines
3.9 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
test('로그인 API 호출 추적', async ({ page }) => {
|
|
console.log('\n╔════════════════════════════════════════════════════╗');
|
|
console.log('║ 로그인 API 호출 추적 & 디버깅 ║');
|
|
console.log('╚════════════════════════════════════════════════════╝\n');
|
|
|
|
// 네트워크 요청 추적
|
|
const requests: string[] = [];
|
|
page.on('request', request => {
|
|
if (request.url().includes('api')) {
|
|
console.log(`📤 Request: ${request.method()} ${request.url()}`);
|
|
requests.push(`${request.method()} ${request.url()}`);
|
|
}
|
|
});
|
|
|
|
page.on('response', response => {
|
|
if (response.url().includes('api')) {
|
|
console.log(`📥 Response: ${response.status()} ${response.url()}`);
|
|
}
|
|
});
|
|
|
|
// 페이지 접근
|
|
console.log('1️⃣ 로그인 페이지 접근...');
|
|
await page.goto('http://localhost:5265/login');
|
|
await page.waitForLoadState('networkidle');
|
|
await page.waitForTimeout(1000);
|
|
|
|
// 입력 및 로그인
|
|
console.log('\n2️⃣ 로그인 시도...');
|
|
const usernameInput = page.locator('input[type="text"]').first();
|
|
const passwordInput = page.locator('input[type="password"]');
|
|
const loginButton = page.locator('button:has-text("로그인")');
|
|
|
|
await usernameInput.fill('admin');
|
|
await passwordInput.fill('admin');
|
|
|
|
console.log('📝 입력 완료: admin / admin');
|
|
|
|
// 로그인 버튼 클릭 전 요청 모니터
|
|
console.log('\n3️⃣ 로그인 버튼 클릭...');
|
|
|
|
// 네트워크 응답 대기
|
|
const [response] = await Promise.all([
|
|
page.waitForResponse(
|
|
response =>
|
|
response.url().includes('/api/auth/login') &&
|
|
(response.status() === 200 || response.status() === 401 || response.status() === 400),
|
|
{ timeout: 10000 }
|
|
),
|
|
loginButton.click()
|
|
]).catch(err => {
|
|
console.log('❌ 응답 대기 실패:', err.message);
|
|
return [null];
|
|
});
|
|
|
|
if (response) {
|
|
console.log(`\n✅ 로그인 API 응답: ${response.status()}`);
|
|
|
|
const responseText = await response.text();
|
|
console.log(`📄 응답 본문: ${responseText}`);
|
|
|
|
try {
|
|
const json = JSON.parse(responseText);
|
|
console.log('🔍 파싱된 JSON:');
|
|
console.log(JSON.stringify(json, null, 2));
|
|
} catch (e) {
|
|
console.log('❌ JSON 파싱 실패');
|
|
}
|
|
} else {
|
|
console.log('❌ 로그인 API 응답 없음');
|
|
}
|
|
|
|
// 최종 상태 확인
|
|
console.log('\n4️⃣ 최종 상태 확인...');
|
|
await page.waitForTimeout(2000);
|
|
|
|
const finalUrl = page.url();
|
|
const finalTitle = await page.title();
|
|
const bodyText = await page.locator('body').textContent();
|
|
|
|
console.log(`📍 최종 URL: ${finalUrl}`);
|
|
console.log(`📄 최종 제목: ${finalTitle}`);
|
|
console.log(`📝 "대시보드" 포함: ${bodyText?.includes('대시보드') ? '✅ 예' : '❌ 아니오'}`);
|
|
console.log(`📝 "로그인" 포함: ${bodyText?.includes('로그인') ? '✅ 예' : '❌ 아니오'}`);
|
|
|
|
// 스크린샷
|
|
await page.screenshot({ path: 'test-results/debug-login.png', fullPage: true });
|
|
console.log('\n📸 스크린샷 저장: test-results/debug-login.png');
|
|
|
|
console.log('\n╔════════════════════════════════════════════════════╗');
|
|
if (finalUrl.includes('/dashboard')) {
|
|
console.log('║ ✅ 로그인 성공! ║');
|
|
} else {
|
|
console.log('║ ❌ 로그인 실패 ║');
|
|
}
|
|
console.log('╚════════════════════════════════════════════════════╝\n');
|
|
});
|