import { chromium } from 'playwright'; import { readFileSync } from 'fs'; const BROWSER = await chromium.launch({ headless: true }); const PAGE = await BROWSER.newPage(); const logs = []; PAGE.on('console', msg => logs.push(`[${msg.type()}] ${msg.text()}`)); PAGE.on('pageerror', err => logs.push(`[PAGE_ERROR] ${err.message}`)); const BASE = 'http://localhost:5174/pindou/'; // ===== STEP 1: Load index page, inject test image into store ===== console.log('=== STEP 1: Load index page ==='); await PAGE.goto(`${BASE}#/`, { waitUntil: 'networkidle', timeout: 15000 }); await PAGE.waitForTimeout(1500); // Create a simple test image data URL (a small colored PNG) // Use page.evaluate to create a canvas, draw something, and get data URL const imageDataUrl = await PAGE.evaluate(() => { const canvas = document.createElement('canvas'); canvas.width = 100; canvas.height = 100; const ctx = canvas.getContext('2d'); // Draw a gradient const gradient = ctx.createLinearGradient(0, 0, 100, 100); gradient.addColorStop(0, '#ff0000'); gradient.addColorStop(0.25, '#00ff00'); gradient.addColorStop(0.5, '#0000ff'); gradient.addColorStop(0.75, '#ffff00'); gradient.addColorStop(1, '#ff00ff'); ctx.fillStyle = gradient; ctx.fillRect(0, 0, 100, 100); return canvas.toDataURL('image/png'); }); console.log('Test image created:', imageDataUrl.substring(0, 50) + '...'); // Inject image into store via sessionStorage await PAGE.evaluate((img) => { sessionStorage.setItem('bead-process-state', JSON.stringify({ sourceImage: img, extractedImage: null, canvasWidth: 29, canvasHeight: 29, fitMode: 'fit', grid: [], legend: [], totalBeads: 0, usedColors: 0, status: 'idle', })); }, imageDataUrl); // Navigate to editor page console.log('\n=== STEP 2: Navigate to editor ==='); await PAGE.goto(`${BASE}#/pages/editor/editor`, { waitUntil: 'networkidle', timeout: 15000 }); await PAGE.waitForTimeout(1500); // Check editor state const editorState = await PAGE.evaluate(() => { const buttons = Array.from(document.querySelectorAll('uni-button, button, [class*="btn"]')) .map(b => ({ text: b.textContent?.trim(), visible: b.offsetParent !== null })); const inputs = Array.from(document.querySelectorAll('input, uni-input')) .map(i => ({ type: i.type, value: i.value, placeholder: i.placeholder })); return { buttons, inputs }; }); console.log('Editor state:', JSON.stringify(editorState, null, 2)); // Try to find and click the "生成图纸" button const genBtn = await PAGE.evaluate(() => { const all = Array.from(document.querySelectorAll('uni-button, button, uni-view, uni-text, view, text')); const btn = all.find(el => el.textContent?.includes('生成图纸')); return btn ? { found: true, tag: btn.tagName, text: btn.textContent?.trim() } : { found: false }; }); console.log('Generate button:', JSON.stringify(genBtn)); if (genBtn.found) { // Click the generate button const clicked = await PAGE.evaluate(() => { const all = Array.from(document.querySelectorAll('uni-button, button, uni-view, uni-text, view, text')); const btn = all.find(el => el.textContent?.includes('生成图纸')); if (btn) { btn.click(); return true; } return false; }); console.log('Clicked generate button:', clicked); await PAGE.waitForTimeout(500); } // Check if we navigated const currentHash = await PAGE.evaluate(() => window.location.hash); console.log('Current hash after click:', currentHash); // If not navigated, manually go to processing if (!currentHash.includes('processing')) { console.log('\n=== STEP 3: Manually navigate to processing ==='); await PAGE.goto(`${BASE}#/pages/processing/processing`, { waitUntil: 'networkidle', timeout: 15000 }); await PAGE.waitForTimeout(2000); } // Check processing page const procState = await PAGE.evaluate(() => { const progressEl = document.querySelector('[class*="progress"]'); const statusEl = document.querySelector('[class*="status"]'); const allText = document.body?.textContent?.substring(0, 500); return { hash: window.location.hash, progressText: progressEl?.textContent?.trim(), statusText: statusEl?.textContent?.trim(), bodyText: allText, }; }); console.log('Processing state:', JSON.stringify(procState, null, 2)); // Wait for processing to complete (up to 10 seconds) let done = false; for (let i = 0; i < 10; i++) { await PAGE.waitForTimeout(1000); const hash = await PAGE.evaluate(() => window.location.hash); if (hash.includes('result')) { console.log('Navigated to result page!'); done = true; break; } const procStatus = await PAGE.evaluate(() => document.body?.textContent?.substring(0, 200)); console.log(` Wait ${i+1}s: hash=${hash}, body=${procStatus}`); } if (!done) { console.log('Processing did not auto-navigate. Checking sessionStorage...'); const ssData = await PAGE.evaluate(() => { const raw = sessionStorage.getItem('bead-process-state'); if (!raw) return null; const d = JSON.parse(raw); return { gridLength: d.grid?.length, totalBeads: d.totalBeads, status: d.status }; }); console.log('sessionStorage state:', JSON.stringify(ssData)); // Force navigate to result await PAGE.goto(`${BASE}#/pages/result/result`, { waitUntil: 'networkidle', timeout: 15000 }); await PAGE.waitForTimeout(2000); } // ===== STEP 4: Check result page ===== console.log('\n=== STEP 4: Result page ==='); const resultState = await PAGE.evaluate(() => { const canvasInner = document.querySelector('.canvas-inner'); const allCanvases = Array.from(document.querySelectorAll('canvas')); const emptyState = document.querySelector('.empty-state'); const infoBar = document.querySelector('.info-bar'); return { hash: window.location.hash, emptyStateVisible: !!emptyState && emptyState.offsetParent !== null, emptyStateText: emptyState?.textContent?.trim(), infoBarText: infoBar?.textContent?.trim(), canvasInnerHTML: canvasInner?.innerHTML?.substring(0, 300), canvasInnerChildCount: canvasInner?.children?.length, canvasCount: allCanvases.length, canvases: allCanvases.map(c => ({ w: c.width, h: c.height })), }; }); console.log(JSON.stringify(resultState, null, 2)); // Print relevant logs console.log('\n=== Relevant Logs ==='); logs.filter(l => l.includes('BeadPattern') || l.includes('result.vue') || l.includes('processStore') || l.includes('pipeline') || l.includes('PAGE_ERROR') || l.includes('Processing') || l.includes('renderCanvas') || l.includes('setResult') || l.includes('saveToStorage') || l.includes('Restored') || l.includes('hasValidData') || l.includes('Grid watch') ).forEach(l => console.log(l)); await PAGE.screenshot({ path: '/Users/guchen/.openclaw/workspace/pindou-flow-debug.png', fullPage: true }); console.log('\nScreenshot saved to pindou-flow-debug.png'); await BROWSER.close();