d3ro-voice/apps/desktop/run_e2e_full_suite.cjs
Yun Chan 708e20f747
Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped
feat: complete release preparation, 10+ ad mediation, CI/CD, and docker deployment
2026-08-20 11:12:05 +09:00

147 lines
4.4 KiB
JavaScript

const fs = require('fs');
const http = require('http');
const WebSocket = require('ws');
const path = require('path');
const ARTIFACTS_DIR = "C:\\Users\\encep\\.gemini\\antigravity\\brain\\8f83f382-c9ee-4ef3-8e9b-a7dec5371b5a";
function getTargets() {
return new Promise((resolve, reject) => {
http.get('http://127.0.0.1:9222/json/list', (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve(JSON.parse(data)));
}).on('error', reject);
});
}
function sendCDP(ws, method, params = {}) {
return new Promise((resolve, reject) => {
const id = Math.floor(Math.random() * 1000000);
const handler = (data) => {
const msg = JSON.parse(data);
if (msg.id === id) {
ws.removeListener('message', handler);
if (msg.error) reject(msg.error);
else resolve(msg.result);
}
};
ws.on('message', handler);
ws.send(JSON.stringify({ id, method, params }));
});
}
async function runFullSuite() {
const targets = await getTargets();
const mainTarget = targets.find(t => t.title === 'D3RO Voice' || t.url.includes('index.html'));
if (!mainTarget) {
console.error('Target not found:', targets);
return;
}
const wsUrl = mainTarget.webSocketDebuggerUrl.replace('localhost', '127.0.0.1');
const ws = new WebSocket(wsUrl);
await new Promise((resolve) => ws.on('open', resolve));
console.log('--- STARTING FULL E2E VISUAL TEST SUITE ---');
await sendCDP(ws, 'Page.enable');
await sendCDP(ws, 'Runtime.enable');
const errors = [];
ws.on('message', (data) => {
try {
const msg = JSON.parse(data);
if (msg.method === 'Runtime.consoleAPICalled' && msg.params.type === 'error') {
const errText = msg.params.args.map(a => a.value || a.description || JSON.stringify(a)).join(' ');
console.error('[RENDERER CONSOLE ERROR DETECTED]:', errText);
errors.push(errText);
}
} catch(e){}
});
const captureScreen = async (filename) => {
try {
const shot = await sendCDP(ws, 'Page.captureScreenshot', { format: 'png' });
const targetPath = path.join(ARTIFACTS_DIR, filename);
fs.writeFileSync(targetPath, Buffer.from(shot.data, 'base64'));
console.log(`[Screen Captured] ${filename}`);
} catch(e) {
console.error(`Failed to capture ${filename}:`, e.message);
}
};
// 1. Initial Dashboard
await captureScreen('page_1_dashboard.png');
// 2. Dismiss modal
try {
await sendCDP(ws, 'Runtime.evaluate', {
expression: `
(() => {
const btns = Array.from(document.querySelectorAll('button'));
const laterBtn = btns.find(b => b.innerText.includes('나중에'));
if (laterBtn) laterBtn.click();
})()
`
});
} catch(e) {
console.error('Modal dismiss error:', e.message);
}
await new Promise(r => setTimeout(r, 600));
await captureScreen('page_1_dashboard_clean.png');
// 3. Test Navigation Tabs
const menuItems = ['히스토리', '사전', '명령어', '대화', '지식 베이스', '회의', '설정'];
for (let i = 0; i < menuItems.length; i++) {
const item = menuItems[i];
console.log(`Navigating to tab: ${item}`);
try {
await sendCDP(ws, 'Runtime.evaluate', {
expression: `
(() => {
const elements = Array.from(document.querySelectorAll('div, span, p, a, button'));
const el = elements.find(e => e.innerText && e.innerText.trim() === '${item}');
if (el) {
el.click();
return true;
}
return false;
})()
`
});
} catch(e) {
console.error(`Tab click error (${item}):`, e.message);
}
await new Promise(r => setTimeout(r, 800));
await captureScreen(`page_${i + 2}_${item.replace(/\s+/g, '_')}.png`);
}
// 4. Test Subtab
console.log('Testing Settings Sub-Tabs...');
try {
await sendCDP(ws, 'Runtime.evaluate', {
expression: `
(() => {
const tabs = Array.from(document.querySelectorAll('button, div[role="tab"]'));
if (tabs.length > 0) tabs[0].click();
})()
`
});
} catch(e){}
await new Promise(r => setTimeout(r, 500));
await captureScreen('page_settings_subtab.png');
console.log('--- E2E TEST SUITE FINISHED ---');
console.log('Total Console Errors Detected during flow:', errors.length);
ws.close();
}
runFullSuite().catch(err => {
console.error('Suite error:', err);
process.exit(1);
});