#!/usr/bin/env node "use strict"; const fs = require("node:fs/promises"); const path = require("node:path"); const { chromium } = require("playwright"); const { BASE_URL, UI_TIMEOUT_MS, assert, cleanupDocuments, createTempDocument, ensureAuthenticated, openDocument, openFilesystemView, renameDocument, requestJson, } = require("./tree-shell-smoke-helpers"); const TASK = "task443-filetree-mindmap-click-active-row-smoke"; const OUT_DIR = path.join(process.cwd(), "tmp", TASK); const RESULT_PATH = path.join(OUT_DIR, "result.json"); async function writeResult(result) { await fs.mkdir(OUT_DIR, { recursive: true }); await fs.writeFile(RESULT_PATH, `${JSON.stringify({ ...result, resultPath: RESULT_PATH }, null, 2)}\n`, "utf8"); } async function createMindmap(request, workspaceId, documentId, mindmapId, title) { return await requestJson(request, `/api/mindmap/${encodeURIComponent(documentId)}/${encodeURIComponent(mindmapId)}`, { method: "POST", data: { commandName: "mindmaps.put", workspaceId, createOnly: true, data: { root: { data: { text: title }, children: [] } }, }, }); } async function readSelectedFileTreeRows(page) { return await page.evaluate(() => Array.from(document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-selected="true"]')).map((row) => ({ rowId: row.getAttribute("data-row-id") || "", rowKind: row.getAttribute("data-row-kind") || "", docId: row.getAttribute("data-document-id") || row.getAttribute("data-doc-id") || "", assetId: row.getAttribute("data-asset-id") || "", objectIdentity: row.getAttribute("data-object-identity") || "", title: (row.textContent || "").trim().slice(0, 160), })), ); } (async () => { await fs.mkdir(OUT_DIR, { recursive: true }); const browser = await chromium.launch({ headless: true }); const context = await browser.newContext({ viewport: { width: 1440, height: 900 } }); const page = await context.newPage(); const navEvents = []; const network = []; page.on("framenavigated", (frame) => { if (frame === page.mainFrame()) navEvents.push({ at: Date.now(), url: frame.url() }); }); page.on("request", (request) => { const url = request.url(); if (url.includes("/mindmap/") || url.includes("/documents/") || url.includes("/api/tree/events")) { network.push({ type: "request", method: request.method(), url }); } }); let doc = null; const result = { baseUrl: BASE_URL, fixture: {}, beforeSelectedRows: [], afterSelectedRows: [], navEvents, network, screenshots: [], }; try { await ensureAuthenticated(page, context.request); doc = await createTempDocument(context.request, null); const stamp = Date.now().toString().slice(-8); const title = `TEST-443-mindmap-active-${stamp}`; await renameDocument(context.request, doc.workspaceId, doc.documentId, title); const mindmapId = `mindmap_443_active_${stamp}`; await createMindmap(context.request, doc.workspaceId, doc.documentId, mindmapId, `TEST-443-mind-${stamp}`); result.fixture = { ...doc, title, mindmapId }; await openDocument(page, doc.workspaceId, doc.documentId); await openFilesystemView(page); await page.waitForSelector(`#sidebar-file-tree-root .tree-row[data-asset-id="${mindmapId}"]`, { timeout: UI_TIMEOUT_MS }); result.beforeSelectedRows = await readSelectedFileTreeRows(page); await page.click(`#sidebar-file-tree-root .tree-row[data-asset-id="${mindmapId}"] .tree-link`, { timeout: UI_TIMEOUT_MS }); await page.waitForFunction( ({ documentId, mindmapId }) => { const url = new URL(window.location.href); if (!url.pathname.includes(`/documents/${encodeURIComponent(documentId)}`)) return false; const rt = url.searchParams.get("resourceTab") || ""; if (!rt) return false; return decodeURIComponent(rt).includes(`resource:mindmap:${documentId}:${mindmapId}`); }, { documentId: doc.documentId, mindmapId }, { timeout: UI_TIMEOUT_MS }, ); await page.waitForSelector(`#sidebar-file-tree-root .tree-row[data-asset-id="${mindmapId}"][data-selected="true"]`, { timeout: UI_TIMEOUT_MS, }); result.afterUrl = page.url(); result.afterSelectedRows = await readSelectedFileTreeRows(page); const screenshotPath = path.join(OUT_DIR, "after-mindmap-click.png"); await page.screenshot({ path: screenshotPath, fullPage: true }); result.screenshots.push(screenshotPath); assert( result.afterSelectedRows.some((row) => row.rowId === `asset:${mindmapId}` && row.assetId === mindmapId), `点击 mindmap 文件行后应保持 asset row 选中: ${JSON.stringify(result.afterSelectedRows)}`, ); assert( !result.afterSelectedRows.some((row) => row.rowId === `doc:${doc.documentId}`), `点击 mindmap 文件行后不应闪回父页面行选中: ${JSON.stringify(result.afterSelectedRows)}`, ); await writeResult({ ...result, ok: true }); console.log(`ok ${TASK} ${RESULT_PATH}`); } catch (error) { await writeResult({ ...result, ok: false, error: error instanceof Error ? error.stack || error.message : String(error), currentUrl: page.url(), }); throw error; } finally { if (doc) await cleanupDocuments(context.request, [doc.documentId]).catch(() => null); await browser.close().catch(() => null); } })().catch((error) => { console.error(error instanceof Error ? error.stack || error.message : error); process.exit(1); });