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>
73 lines
4.7 KiB
TypeScript
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));
|
|
});
|