const { chromium } = require('@playwright/test'); const path = require('path'); const fs = require('fs'); const http = require('http'); const RENDERER_DIST = path.resolve(__dirname, '../apps/desktop/out/renderer'); const SCREENSHOT_DIR = 'C:/Users/encep/.gemini/antigravity-cli/brain/3ab7ae82-5634-41d5-93a7-3c12c22503e2/screenshots'; // MIME types const MIME_TYPES = { '.html': 'text/html', '.js': 'application/javascript', '.css': 'text/css', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml', '.woff2': 'font/woff2', '.woff': 'font/woff', '.ttf': 'font/ttf', }; // Start simple static file server for desktop renderer function startServer() { return new Promise((resolve) => { const server = http.createServer((req, res) => { let reqPath = req.url.split('?')[0]; if (reqPath === '/' || reqPath === '') reqPath = '/index.html'; const filePath = path.join(RENDERER_DIST, reqPath); if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) { const ext = path.extname(filePath).toLowerCase(); res.writeHead(200, { 'Content-Type': MIME_TYPES[ext] || 'application/octet-stream' }); fs.createReadStream(filePath).pipe(res); } else { res.writeHead(404); res.end('Not Found'); } }); server.listen(0, '127.0.0.1', () => { const port = server.address().port; console.log(`Desktop renderer server running at http://127.0.0.1:${port}`); resolve({ server, port }); }); }); } async function capture() { if (!fs.existsSync(SCREENSHOT_DIR)) { fs.mkdirSync(SCREENSHOT_DIR, { recursive: true }); } const { server, port } = await startServer(); const browser = await chromium.launch({ channel: 'msedge', headless: true }); const context = await browser.newContext({ viewport: { width: 1280, height: 800 }, deviceScaleFactor: 2, // High-DPI crisp capture }); const page = await context.newPage(); page.on('console', (msg) => console.log('BROWSER LOG:', msg.text())); page.on('pageerror', (err) => console.log('BROWSER ERROR STACK:', err.stack)); // Inject comprehensive recursive Proxy for window.electronAPI await page.addInitScript(() => { function createMockProxy(path = []) { const targetFn = (...args) => { const lastProp = path[path.length - 1] || ''; if (lastProp.startsWith('on') || lastProp.startsWith('remove') || lastProp.startsWith('off')) { return () => {}; // unsubscription function } if (lastProp === 'getAll' || lastProp === 'get') { return Promise.resolve({ success: true, data: { onboardingCompleted: true, theme: 'dark', language: 'ko', appUsageMode: 'online', llmBackend: 'online', sttProvider: 'whisper_local', tier: 'free', entries: [ { id: '1', originalText: 'D3RO Voice 실시간 음성 인식 테스트 중입니다. Free Tier 광고 배너가 표시됩니다.', polishedText: 'D3RO Voice 실시간 음성 인식 테스트 중입니다. Free Tier 광고 배너가 표시됩니다.', text: 'D3RO Voice 실시간 음성 인식 테스트 중입니다. Free Tier 광고 배너가 표시됩니다.', rawText: 'D3RO Voice 실시간 음성 인식 테스트 중입니다. Free Tier 광고 배너가 표시됩니다.', createdAt: Date.now() - 1000 * 60 * 5, durationMs: 4200, charCount: 45, wordsPerMinute: 195, mode: 'general', tags: [], favorite: false, }, ], }, }); } if (lastProp === 'getSummary') { return Promise.resolve({ success: true, data: { totalTranscriptions: 48, totalDurationMs: 182000, totalCharacters: 2840, wordsPerMinute: 195, savedMinutes: 62, todayTranscriptions: 12, todayDurationMs: 45000, }, }); } if (lastProp === 'getAllUsage') { return Promise.resolve({ success: true, data: [{ feature: 'cloud_llm', current: 45, max: 250, unit: 'tokens' }], }); } if (lastProp === 'getActiveModel') return Promise.resolve({ success: true, data: 'large-v3-turbo' }); if (lastProp === 'getDictationShortcut') { return Promise.resolve({ success: true, data: { id: 'dictation', key: 'Alt+V', enabled: true } }); } if (lastProp === 'getState') return Promise.resolve({ success: true, data: 'idle' }); if (lastProp === 'getMode') return Promise.resolve({ success: true, data: 'general' }); if (lastProp === 'getTheme') return Promise.resolve({ success: true, data: 'dark' }); if (lastProp === 'getLanguage') return Promise.resolve({ success: true, data: 'ko' }); if (lastProp === 'getStatus') { return Promise.resolve({ success: true, data: { status: 'ready', connectionState: 'connected', model: 'large-v3-turbo', available: true, backend: 'local' }, }); } if (lastProp === 'getInfo' || lastProp === 'getLicenseInfo' || lastProp === 'getTier') { return Promise.resolve({ success: true, data: { tier: 'free', valid: true, expiresAt: null, remainingTokens: 45, maxTokens: 250 }, }); } if (lastProp === 'getDevices' || lastProp === 'list' || lastProp === 'getModels') { return Promise.resolve({ success: true, data: [ { id: 'default', name: 'Realtek High Definition Audio (Default)', isDefault: true }, { id: 'large-v3-turbo', name: 'large-v3-turbo', size: '1.5GB', downloaded: true }, ], }); } if (lastProp === 'isMaximized') return Promise.resolve({ success: true, data: false }); if (lastProp === 'getVersion') return Promise.resolve({ success: true, data: '1.0.0' }); return Promise.resolve({ success: true, data: [] }); }; return new Proxy(targetFn, { get(target, prop) { if (prop === 'platform') return 'win32'; if (prop === 'then') return undefined; // avoid promise confusion if (typeof prop === 'string' && (prop.startsWith('on') || prop.startsWith('remove') || prop.startsWith('off'))) { return () => () => {}; } return createMockProxy([...path, prop]); }, }); } window.electronAPI = createMockProxy(); }); console.log(`Navigating to Desktop App at http://127.0.0.1:${port}/index.html...`); await page.goto(`http://127.0.0.1:${port}/index.html`); await page.waitForTimeout(2000); // 1. Capture Main App Window with Free Tier Banner at bottom dock console.log('Capturing Screenshot 1: Desktop App with Ad Banner in dock...'); await page.screenshot({ path: path.join(SCREENSHOT_DIR, '11_actual_desktop_app_with_banner.png'), }); // 2. Focus on AdBanner Component specifically console.log('Capturing Screenshot 2: Focused AdBanner Component...'); const adCard = page.locator('text=/Cursor AI/').first(); if (await adCard.isVisible()) { await adCard.screenshot({ path: path.join(SCREENSHOT_DIR, '12_actual_desktop_adbanner_focused.png'), }); } // 3. Click Customer Support in sidebar to show SupportModal console.log('Capturing Screenshot 3: Customer Support Modal...'); const supportNav = page.locator('text=/Customer Support/').first(); if (await supportNav.isVisible()) { await supportNav.click(); await page.waitForTimeout(800); await page.screenshot({ path: path.join(SCREENSHOT_DIR, '13_actual_desktop_support_modal.png'), }); await page.keyboard.press('Escape'); await page.waitForTimeout(400); } // 4. Click "Remove ads with Pro" on banner to show CheckoutModal console.log('Capturing Screenshot 4: Checkout Modal...'); const removeAdsLink = page.locator('text=/Remove ads with Pro/').first(); if (await removeAdsLink.isVisible()) { await removeAdsLink.click(); await page.waitForTimeout(800); await page.screenshot({ path: path.join(SCREENSHOT_DIR, '14_actual_desktop_checkout_modal.png'), }); await page.keyboard.press('Escape'); await page.waitForTimeout(400); } await browser.close(); server.close(); console.log('All 4 actual desktop app screenshots captured successfully!'); } capture().catch((err) => { console.error(err); process.exit(1); });