Files
workinf_Blender_Wasm/web/tests/e2e/console-dispatch-diagnostic.spec.ts
mes123456 f3e21c6b98
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
chore: checkpoint web Blender migration source, tools and docs
Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer,
web workflow engine and protocol, tooling, docs and task records.
Large generated evidence, user-testing archives, build snapshots and
imported test assets remain untracked.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-11-10 11:18:01 +08:00

73 lines
4.7 KiB
TypeScript

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<string, unknown> = {};
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));
});