const { chromium } = require('playwright'); const { loginViaAuthForm } = require('./lib/browser-auth-login'); (async () => { const browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] }); const page = await browser.newPage({ viewport: { width: 1280, height: 800 } }); const consoleErrors = []; page.on('console', msg => { if (msg.type() === 'error') consoleErrors.push(msg.text()); }); const testErrors = []; page.on('pageerror', err => testErrors.push(err.message)); // 7-76:标准表单登录(无快速登录按钮) await page.goto('http://localhost:3000/auth', { waitUntil: 'domcontentloaded' }); await page.waitForTimeout(2000); if (await page.locator('#account').count()) { await loginViaAuthForm(page, { baseUrl: 'http://localhost:3000', gotoAuth: false }); await page.waitForTimeout(3000); } // Navigate to QA test page await page.goto('http://localhost:3000/w/mnote-e2e/qa-block-handle-test', { waitUntil: 'domcontentloaded' }); await page.waitForTimeout(3000); console.log('Final URL:', page.url()); const editor = await page.$('.ProseMirror'); console.log('ProseMirror found:', !!editor); if (editor) { const editorRect = await editor.boundingBox(); console.log('Editor rect:', JSON.stringify(editorRect)); const paragraphs = await editor.$$('p'); console.log('Paragraph count:', paragraphs.length); if (paragraphs.length > 0) { const pRect = await paragraphs[0].boundingBox(); console.log('First P rect:', JSON.stringify(pRect)); // Hover over paragraph at the left edge area await page.mouse.move(pRect.x + 5, pRect.y + pRect.height/2); await page.waitForTimeout(800); const handleShell = await page.$('[data-testid="mnote-leptos-tiptap-handle"]'); console.log('Handle shell found:', !!handleShell); if (handleShell) { const hRect = await handleShell.boundingBox(); console.log('Handle rect:', JSON.stringify(hRect)); const display = await handleShell.evaluate(el => getComputedStyle(el).display); const visibility = await handleShell.evaluate(el => getComputedStyle(el).visibility); const opacity = await handleShell.evaluate(el => getComputedStyle(el).opacity); const pointerEvents = await handleShell.evaluate(el => getComputedStyle(el).pointerEvents); console.log('CSS: display=' + display + ' vis=' + visibility + ' op=' + opacity + ' pe=' + pointerEvents); await page.screenshot({ path: '/tmp/handle-shell-found.png', fullPage: false }); const trigger = await handleShell.$('[data-testid="block-drag-handle-trigger"]'); console.log('Trigger found:', !!trigger); if (trigger) { const tRect = await trigger.boundingBox(); console.log('Trigger rect:', JSON.stringify(tRect)); // Click await trigger.click({ force: true }); await page.waitForTimeout(1000); const blockMenu = await page.$('[data-testid="block-drag-menu"]'); console.log('Block menu found:', !!blockMenu); if (blockMenu) { const bmRect = await blockMenu.boundingBox(); console.log('Block menu rect:', JSON.stringify(bmRect)); const menuItems = await blockMenu.$$('[data-testid^="block-drag-menu-item"]'); console.log('Menu items count:', menuItems.length); const iconSpans = await blockMenu.$$('.block-drag-menu-icon'); console.log('Icon spans count:', iconSpans.length); for (const item of menuItems) { const text = await item.textContent(); const icon = await item.$('.material-symbols-outlined'); const icon2 = await item.$('[data-testid^="block-drag-menu-icon"]'); console.log(' Item text="' + (text ? text.trim().substring(0,40) : '') + '" icon=' + !!icon); } await page.screenshot({ path: '/tmp/block-menu-open.png', fullPage: false }); } else { // Check what's rendered const stage = await page.$('[data-testid="mnote-leptos-tiptap-editor-stage"]'); const stageHTML = await stage.evaluate(el => el.innerHTML.substring(0, 3000)); console.log('Stage HTML after click (3K):', stageHTML.substring(0, 1000) + '...'); // Check for menu elements anywhere const allMenus = await page.$$('[class*="menu"]'); console.log('Any menu elements on page:', allMenus.length); } } } else { // Check stage innerHTML const stage = await page.$('[data-testid="mnote-leptos-tiptap-editor-stage"]'); console.log('Stage found:', !!stage); if (stage) { const html = await stage.evaluate(el => el.innerHTML.substring(0, 2000)); console.log('Stage HTML:', html); } } } } console.log('Console errors:', consoleErrors.length); console.log('Page errors:', testErrors.length); await browser.close(); })().catch(e => { console.error('CRASH:', e.message); process.exit(1); });