Files
val-blog/debug-pindou-flow.mjs
T

187 lines
6.8 KiB
JavaScript

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();