import { test, expect } from '@playwright/test'; import fs from 'node:fs'; import path from 'node:path'; /* Temporary diagnostic: the console reports no dispatch, no echo and no error. * Count the real DOM nodes before and after switching to the Scripting workspace. */ test('console dispatch diagnostic', async ({ page }, info) => { const record: Record = {}; const consoleErrors: string[] = []; record.consoleErrors = consoleErrors; page.on('console', message => { if (message.type() === 'error') consoleErrors.push(message.text().slice(0, 300)); }); const probe = () => page.evaluate(() => ({ consoleRegion: document.querySelectorAll('[aria-label="Python Console"]').length, wasmConsole: document.querySelectorAll('.wasm-python-console').length, pythonInput: document.querySelectorAll('[aria-label="Python 输入"]').length, promptMarks: (document.body.innerText.match(/>>>/g) ?? []).length, bodyLen: document.body.innerText.length, bodyTail: document.body.innerText.slice(-600), pressedDesktop: document.querySelector('[aria-label="工作区显示"] button')?.getAttribute('aria-pressed') ?? null, pressedWeb: document.querySelectorAll('[aria-label="工作区显示"] button')[1]?.getAttribute('aria-pressed') ?? null, workspaceNodes: document.querySelectorAll('[class*="workspace"]').length, sourceWorkspace: document.querySelectorAll('.wasm-source-workspace').length, editors: Array.from(document.querySelectorAll('[data-editor]')).map(n => n.getAttribute('data-editor')), dataWorkspace: document.querySelector('main')?.getAttribute('data-workspace') ?? null, areas: Array.from(document.querySelectorAll('[data-area-editor], .area')).slice(0,20).map(n => n.className), })); await page.goto('/'); await page.getByTestId('blend-file-input').setInputFiles(path.resolve(import.meta.dirname, '../../../tests/files/web/basic_scene.blend')); await expect(page.getByTestId('engine-status')).toContainText(/SceneIR/, { timeout: 60_000 }); record.afterLoad = await probe(); const webTools = page.getByTestId('native-web-tools-toggle'); record.webToolsCount = await webTools.count(); await webTools.click({ force: true }).catch(() => {}); await page.waitForTimeout(1500); record.afterToolsToggle = await probe(); const scriptTab = page.getByRole('button', { name: 'Scripting', exact: true }).first(); record.scriptingCount = await page.getByRole('button', { name: 'Scripting', exact: true }).count(); record.scriptingDisabled = await scriptTab.isDisabled().catch(() => null); record.scriptingCurrentBefore = await scriptTab.getAttribute('aria-current').catch(() => null); record.statusBefore = await page.getByTestId('engine-status').textContent().catch(() => null); const timeline = []; const snap = async (label: string) => timeline.push({ label, ws: await page.locator('main').getAttribute('data-workspace'), st: await page.getByTestId('engine-status').textContent().catch(() => null) }); record.domDispatch = await page.evaluate(() => { const btns = Array.from(document.querySelectorAll('nav[aria-label="工作区"] button')); const target = btns.find(b => (b.textContent ?? '').trim() === 'Scripting'); if (!target) return { found: false, names: btns.map(b => (b.textContent ?? '').trim()) }; const r = target.getBoundingClientRect(); const top = document.elementFromPoint(r.x + r.width / 2, r.y + r.height / 2); const info = { found: true, disabled: (target as HTMLButtonElement).disabled, rect: [Math.round(r.x), Math.round(r.y), Math.round(r.width), Math.round(r.height)], topTag: top?.tagName ?? null, topClass: (top as HTMLElement | null)?.className ?? null, topIsTarget: top === target }; target.click(); return info; }); await snap('t+0'); await page.waitForTimeout(400); await snap('t+400'); await page.waitForTimeout(800); await snap('t+1200'); await page.waitForTimeout(1500); await snap('t+2700'); record.timeline = timeline; record.scriptingCurrentAfter = await scriptTab.getAttribute('aria-current').catch(() => null); record.afterScripting = await probe(); const input = page.getByLabel('Python 输入', { exact: true }).last(); if (await input.count()) { await input.fill('print(1 + 1)'); await input.press('Enter'); await page.waitForTimeout(4000); record.valueAfterEnter = await input.inputValue(); record.afterEnter = await probe(); record.alerts = await page.locator('[role="alert"]').allTextContents(); } record.engineStatus = await page.getByTestId('engine-status').textContent().catch(() => null); fs.writeFileSync(info.outputPath('console-diagnostic.json'), JSON.stringify(record, null, 1)); console.log(JSON.stringify(record, null, 1)); });