import { test, expect } from '@playwright/test' test.describe('모든 페이지 종합 검증 (AGENTS.md v16.0)', () => { // 1. HomePage 검증 test('1. HomePage - 국내 기준 상용 수준 검증', async ({ page }) => { await page.goto('/', { waitUntil: 'networkidle' }) await page.screenshot({ path: 'D:\\Temp\\home-validation.png', fullPage: true }) const analysis = await page.evaluate(() => { const h1 = document.querySelector('h1')?.textContent || '' const sections = document.querySelectorAll('section, div[class*="section"], div[class*="kbx-"]').length const ctas = document.querySelectorAll('a[href*="/model-ops"], a[href*="/governance"], button').length const trustedElements = document.querySelectorAll('[class*="trust"], [class*="stat"], [class*="card"]').length return { heroTitle: h1.substring(0, 50), sections, ctas, trustElements: trustedElements, visibleText: document.body.innerText.length, } }) console.log('\n✅ HomePage 분석:') console.log(` Hero Title: "${analysis.heroTitle}"`) console.log(` Sections: ${analysis.sections}`) console.log(` CTAs: ${analysis.ctas}`) console.log(` Trust Elements: ${analysis.trustElements}`) console.log(` Text Length: ${analysis.visibleText}`) expect(analysis.sections).toBeGreaterThan(3) expect(analysis.ctas).toBeGreaterThan(2) }) // 2. ModelList 검증 test('2. ModelList - 마스터 디테일 레이아웃 검증', async ({ page }) => { await page.goto('/model-ops/models-master', { waitUntil: 'networkidle' }) await page.screenshot({ path: 'D:\\Temp\\models-validation.png', fullPage: true }) const analysis = await page.evaluate(() => { const title = document.querySelector('h1')?.textContent || '' const masterItems = document.querySelectorAll('[class*="list"], [class*="item"]').length const detailPanel = document.querySelector('[class*="detail"]')?.textContent?.length || 0 const metrics = document.querySelectorAll('[class*="metric"], [class*="stat"]').length const actions = document.querySelectorAll('button, a[class*="btn"], a[class*="action"]').length return { title: title.substring(0, 40), masterItems, detailPanelTextLength: detailPanel, metrics, actions, } }) console.log('\n✅ ModelList 분석:') console.log(` Title: "${analysis.title}"`) console.log(` Master Items: ${analysis.masterItems}`) console.log(` Detail Panel Content: ${analysis.detailPanelTextLength} chars`) console.log(` Metrics Displayed: ${analysis.metrics}`) console.log(` Action Buttons: ${analysis.actions}`) expect(analysis.masterItems).toBeGreaterThan(0) expect(analysis.actions).toBeGreaterThan(0) }) // 3. ShadowRunQueue 검증 test('3. ShadowRunQueue - 작업 모니터링 검증', async ({ page }) => { await page.goto('/model-ops/shadow-run-jobs', { waitUntil: 'networkidle' }) await page.screenshot({ path: 'D:\\Temp\\shadowrun-validation.png', fullPage: true }) const analysis = await page.evaluate(() => { const title = document.querySelector('h1')?.textContent || '' const statCards = document.querySelectorAll('[class*="stat"]').length const jobCards = document.querySelectorAll('[class*="card"], [class*="job"], article').length const progressBars = document.querySelectorAll('progress, [class*="progress"], [class*="bar"]').length const statusBadges = document.querySelectorAll('[class*="badge"], [class*="status"]').length const filters = document.querySelectorAll('input, select, [class*="filter"]').length return { title: title.substring(0, 40), stats: statCards, jobs: jobCards, progress: progressBars, statusBadges, filters, } }) console.log('\n✅ ShadowRunQueue 분석:') console.log(` Title: "${analysis.title}"`) console.log(` Status Cards: ${analysis.stats}`) console.log(` Job Cards: ${analysis.jobs}`) console.log(` Progress Bars: ${analysis.progress}`) console.log(` Status Badges: ${analysis.statusBadges}`) console.log(` Filters: ${analysis.filters}`) expect(analysis.jobs).toBeGreaterThan(0) expect(analysis.statusBadges).toBeGreaterThan(0) }) // 4. ApprovalQueue 검증 test('4. ApprovalQueue - 승인 워크플로우 검증', async ({ page }) => { await page.goto('/governance/approvals', { waitUntil: 'networkidle' }) await page.screenshot({ path: 'D:\\Temp\\approval-validation.png', fullPage: true }) const analysis = await page.evaluate(() => { const title = document.querySelector('h1')?.textContent || '' const statCards = document.querySelectorAll('[class*="stat"]').length const requestItems = document.querySelectorAll('[class*="request"], [class*="item"], article').length const approveButtons = Array.from(document.querySelectorAll('button, a')).filter(el => el.textContent?.includes('승인') || el.textContent?.includes('Approve') ).length const rejectButtons = Array.from(document.querySelectorAll('button, a')).filter(el => el.textContent?.includes('거부') || el.textContent?.includes('Reject') ).length const metrics = document.querySelectorAll('[class*="metric"], [class*="validation"]').length return { title: title.substring(0, 40), stats: statCards, requests: requestItems, approveActions: approveButtons, rejectActions: rejectButtons, metrics, } }) console.log('\n✅ ApprovalQueue 분석:') console.log(` Title: "${analysis.title}"`) console.log(` Status Cards: ${analysis.stats}`) console.log(` Request Items: ${analysis.requests}`) console.log(` Approve Actions: ${analysis.approveActions}`) console.log(` Reject Actions: ${analysis.rejectActions}`) console.log(` Validation Metrics: ${analysis.metrics}`) expect(analysis.requests).toBeGreaterThan(0) }) // 5. 종합 평가 test('5. 종합 평가 - AGENTS.md v16.0 준수도', async ({ page }) => { const pages = [ { name: 'HomePage', url: '/' }, { name: 'ModelList', url: '/model-ops/models-master' }, { name: 'ShadowRunQueue', url: '/model-ops/shadow-run-jobs' }, { name: 'ApprovalQueue', url: '/governance/approvals' }, ] const results = [] for (const pageInfo of pages) { await page.goto(pageInfo.url, { waitUntil: 'networkidle' }) const metrics = await page.evaluate(() => { // SOLID: 컴포넌트 책임 분리 확인 const uniqueClasses = new Set( Array.from(document.querySelectorAll('*')).map(el => el.className) ) // 필요성 주도: 불필요한 요소 확인 const allElements = document.querySelectorAll('*').length const visibleElements = Array.from(document.querySelectorAll('*')).filter(el => { const style = window.getComputedStyle(el) return style.display !== 'none' && style.visibility !== 'hidden' }).length // 접근성: ARIA 속성 const ariaElements = document.querySelectorAll('[aria-label], [role], [aria-describedby]').length // 반응형: 미디어 쿼리 감지 const hasResponsiveDesign = window.innerWidth < 1024 ? document.querySelectorAll('[class*="mobile"], [class*="responsive"]').length > 0 : true return { solidScore: Math.min(uniqueClasses.size / 20, 1) * 100, necessityScore: Math.min(visibleElements / allElements, 1) * 100, accessibilityScore: Math.min(ariaElements / 20, 1) * 100, responsiveReady: hasResponsiveDesign, } }) results.push({ page: pageInfo.name, ...metrics, }) } console.log('\n📊 종합 평가:') results.forEach(r => { console.log(`\n${r.page}:`) console.log(` SOLID: ${r.solidScore.toFixed(1)}%`) console.log(` 필요성 주도: ${r.necessityScore.toFixed(1)}%`) console.log(` 접근성: ${r.accessibilityScore.toFixed(1)}%`) console.log(` 반응형: ${r.responsiveReady ? '✅' : '⚠️'}`) }) expect(results.length).toBe(4) }) })