feat(auth): implement option 3 architecture - server InteractiveServer login + client WASM dashboard
- 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>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import { test } from '@playwright/test';
|
||||
|
||||
test('로그인 버튼 상태 확인', async ({ page }) => {
|
||||
console.log('\n╔════════════════════════════════════════════════════╗');
|
||||
console.log('║ 로그인 버튼 상태 상세 확인 ║');
|
||||
console.log('╚════════════════════════════════════════════════════╝\n');
|
||||
|
||||
await page.goto('http://localhost:5265/login');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
const loginButton = page.locator('button:has-text("로그인")');
|
||||
|
||||
console.log('1️⃣ 버튼 존재 여부:');
|
||||
const count = await loginButton.count();
|
||||
console.log(` 찾은 버튼 개수: ${count}`);
|
||||
|
||||
if (count > 0) {
|
||||
console.log('\n2️⃣ 버튼 속성:');
|
||||
const isVisible = await loginButton.isVisible();
|
||||
console.log(` 시각성(isVisible): ${isVisible}`);
|
||||
|
||||
const isEnabled = await loginButton.isEnabled();
|
||||
console.log(` 활성화(isEnabled): ${isEnabled}`);
|
||||
|
||||
const isDisabled = await loginButton.evaluate((el: any) => el.disabled);
|
||||
console.log(` Disabled 속성: ${isDisabled}`);
|
||||
|
||||
const text = await loginButton.textContent();
|
||||
console.log(` 버튼 텍스트: "${text}"`);
|
||||
|
||||
const classList = await loginButton.evaluate((el: any) => Array.from(el.classList));
|
||||
console.log(` CSS 클래스: ${classList.join(', ')}`);
|
||||
|
||||
console.log('\n3️⃣ 버튼의 onclick 속성:');
|
||||
const onclick = await loginButton.evaluate((el: any) => el.onclick);
|
||||
console.log(` onclick: ${onclick}`);
|
||||
|
||||
console.log('\n4️⃣ 클릭 시도 (입력 필드 채운 후)...');
|
||||
const usernameInput = page.locator('input[type="text"]').first();
|
||||
const passwordInput = page.locator('input[type="password"]');
|
||||
|
||||
await usernameInput.fill('admin');
|
||||
await passwordInput.fill('admin');
|
||||
|
||||
console.log(' 입력 완료, 버튼 클릭 시도...');
|
||||
|
||||
// 다양한 클릭 방법 시도
|
||||
try {
|
||||
await loginButton.click({ timeout: 5000 });
|
||||
console.log(' ✅ click() 성공');
|
||||
} catch (e) {
|
||||
console.log(` ❌ click() 실패: ${e}`);
|
||||
}
|
||||
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
console.log('\n5️⃣ 최종 상태:');
|
||||
console.log(` URL: ${page.url()}`);
|
||||
console.log(` 제목: ${await page.title()}`);
|
||||
} else {
|
||||
console.log('❌ 로그인 버튼을 찾을 수 없습니다!');
|
||||
}
|
||||
|
||||
// 페이지 HTML 구조 확인
|
||||
console.log('\n6️⃣ 전체 버튼 목록:');
|
||||
const allButtons = page.locator('button');
|
||||
const buttonCount = await allButtons.count();
|
||||
console.log(` 총 버튼 개수: ${buttonCount}`);
|
||||
|
||||
for (let i = 0; i < Math.min(buttonCount, 5); i++) {
|
||||
const btn = allButtons.nth(i);
|
||||
const btnText = await btn.textContent();
|
||||
console.log(` [${i}] ${btnText?.trim()}`);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user