feat: restore Wolai workspace navigation and assets
This commit is contained in:
@@ -78,6 +78,10 @@ function localMarkdownDocumentPath(documentId) {
|
||||
return decodeURIComponent(encoded.replace(/~/g, "%"));
|
||||
}
|
||||
|
||||
function cssEscape(value) {
|
||||
return String(value).replace(/["\\]/g, "\\$&");
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const port = await pickPort();
|
||||
const baseUrl = `http://127.0.0.1:${port}`;
|
||||
@@ -456,6 +460,30 @@ async function main() {
|
||||
);
|
||||
|
||||
await page.evaluate(() => {
|
||||
const root = document.getElementById("sidebar-file-tree-root");
|
||||
const original = Element.prototype.replaceChildren;
|
||||
window.__mnoteRevealReplaceChildrenProbe = {
|
||||
root,
|
||||
original,
|
||||
rootCalls: 0,
|
||||
descendantCalls: [],
|
||||
};
|
||||
Element.prototype.replaceChildren = function(...nodes) {
|
||||
const probe = window.__mnoteRevealReplaceChildrenProbe;
|
||||
if (this === probe.root) {
|
||||
probe.rootCalls += 1;
|
||||
} else if (probe.root?.contains(this)) {
|
||||
probe.descendantCalls.push({
|
||||
className: this instanceof HTMLElement ? this.className : "",
|
||||
relativePath: this.closest(".tree-node")?.querySelector(":scope > .tree-row")?.getAttribute("data-local-relative-path") || "",
|
||||
incomingChildren: nodes.length,
|
||||
});
|
||||
}
|
||||
return probe.original.apply(this, nodes);
|
||||
};
|
||||
window.dispatchEvent(new CustomEvent("mnote:primary-document-activated", {
|
||||
detail: { documentId: "local-md:design~2Freveal-parent~2Fchild~2Fnote.md" },
|
||||
}));
|
||||
window.dispatchEvent(new CustomEvent("mnote:primary-document-activated", {
|
||||
detail: { documentId: "local-md:design~2Freveal-parent~2Fchild~2Fnote.md" },
|
||||
}));
|
||||
@@ -468,7 +496,90 @@ async function main() {
|
||||
&& row.getAttribute("data-focused") === "true"
|
||||
&& row.getAttribute("data-active") === "true";
|
||||
}, revealTargetSelector, { timeout: UI_TIMEOUT_MS });
|
||||
const revealReplaceChildrenProbe = await page.evaluate(() => {
|
||||
const probe = window.__mnoteRevealReplaceChildrenProbe;
|
||||
if (!probe) return null;
|
||||
Element.prototype.replaceChildren = probe.original;
|
||||
return {
|
||||
rootCalls: probe.rootCalls,
|
||||
descendantCalls: probe.descendantCalls,
|
||||
};
|
||||
});
|
||||
assert.equal(
|
||||
revealReplaceChildrenProbe?.rootCalls,
|
||||
0,
|
||||
`打开深层页面只能定位 FileTree,不能替换 FileTree 根节点: ${JSON.stringify(revealReplaceChildrenProbe)}`,
|
||||
);
|
||||
assert.ok(
|
||||
(revealReplaceChildrenProbe?.descendantCalls || []).every((call) => String(call.className).includes("tree-children")),
|
||||
`打开深层页面不能替换 FileTree 的非局部节点: ${JSON.stringify(revealReplaceChildrenProbe)}`,
|
||||
);
|
||||
assert.ok(
|
||||
(revealReplaceChildrenProbe?.descendantCalls || []).length <= 2,
|
||||
`已存在的祖先节点不应在页面打开时被重复重绘: ${JSON.stringify(revealReplaceChildrenProbe)}`,
|
||||
);
|
||||
|
||||
await page.locator('[data-mnote-sidebar-tree-tab="page"]').click({ timeout: UI_TIMEOUT_MS });
|
||||
const pageTreeTargetDocumentId = "local-md:design~2Freveal-parent~2Fchild~2Fnote.md";
|
||||
const pageTreeTargetSelector = `#sidebar-tree-root .tree-row[data-shell-mode="page"][data-node-id="${cssEscape(pageTreeTargetDocumentId)}"]`;
|
||||
await page.locator(pageTreeTargetSelector).waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const pageTreeFileSelectionBeforeOpen = await page.evaluate(() => {
|
||||
const root = document.getElementById("sidebar-file-tree-root");
|
||||
const selected = root?.querySelector('.tree-row[data-selected="true"]');
|
||||
return selected?.getAttribute("data-row-id") || "";
|
||||
});
|
||||
await page.evaluate(() => {
|
||||
const fileRoot = document.getElementById("sidebar-file-tree-root");
|
||||
const pageRoot = document.getElementById("sidebar-tree-root");
|
||||
const original = Element.prototype.replaceChildren;
|
||||
window.__mnotePageTreeOpenProbe = {
|
||||
fileRoot,
|
||||
pageRoot,
|
||||
original,
|
||||
fileRootCalls: 0,
|
||||
pageRootCalls: 0,
|
||||
};
|
||||
Element.prototype.replaceChildren = function(...nodes) {
|
||||
const probe = window.__mnotePageTreeOpenProbe;
|
||||
if (this === probe.fileRoot) probe.fileRootCalls += 1;
|
||||
if (this === probe.pageRoot) probe.pageRootCalls += 1;
|
||||
return probe.original.apply(this, nodes);
|
||||
};
|
||||
});
|
||||
await page.locator(`${pageTreeTargetSelector} .tree-link`).click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction((documentId) => {
|
||||
const activeTab = document.querySelector('[data-mnote-sidebar-tree-tab="page"][aria-selected="true"]');
|
||||
const row = document.querySelector(`#sidebar-tree-root .tree-row[data-shell-mode="page"][data-node-id="${CSS.escape(documentId)}"]`);
|
||||
return activeTab && row && row.getAttribute("data-active") === "true";
|
||||
}, pageTreeTargetDocumentId, { timeout: UI_TIMEOUT_MS });
|
||||
const pageTreeOpenProbe = await page.evaluate(() => {
|
||||
const probe = window.__mnotePageTreeOpenProbe;
|
||||
if (!probe) return null;
|
||||
Element.prototype.replaceChildren = probe.original;
|
||||
const selected = probe.fileRoot?.querySelector('.tree-row[data-selected="true"]');
|
||||
return {
|
||||
fileRootCalls: probe.fileRootCalls,
|
||||
pageRootCalls: probe.pageRootCalls,
|
||||
fileTreeSelection: selected?.getAttribute("data-row-id") || "",
|
||||
};
|
||||
});
|
||||
assert.equal(
|
||||
pageTreeOpenProbe?.fileRootCalls,
|
||||
0,
|
||||
`页面树打开页面时不得全量重建 FileTree: ${JSON.stringify(pageTreeOpenProbe)}`,
|
||||
);
|
||||
assert.equal(
|
||||
pageTreeOpenProbe?.pageRootCalls,
|
||||
0,
|
||||
`页面树打开已加载页面时不得全量重建 PageTree: ${JSON.stringify(pageTreeOpenProbe)}`,
|
||||
);
|
||||
assert.equal(
|
||||
pageTreeOpenProbe?.fileTreeSelection,
|
||||
pageTreeFileSelectionBeforeOpen,
|
||||
`页面树激活时打开页面不得改写 FileTree selection: ${JSON.stringify(pageTreeOpenProbe)}`,
|
||||
);
|
||||
|
||||
await page.locator('[data-mnote-sidebar-tree-tab="filetree"]').click({ timeout: UI_TIMEOUT_MS });
|
||||
const slowScopeSelector = '#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-local-relative-path="design/slow-scope"]';
|
||||
await page.locator(slowScopeSelector).waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.locator(`${slowScopeSelector} [data-rust-action="toggle"]`).click({ timeout: UI_TIMEOUT_MS });
|
||||
@@ -484,8 +595,7 @@ async function main() {
|
||||
const staleRowsInDocsScope = await page.locator('#sidebar-file-tree-root .tree-row[data-local-relative-path^="design/slow-scope/"]').count();
|
||||
assert.equal(staleRowsInDocsScope, 0, "慢请求返回后不得把旧 design scope children patch 到 docs scope");
|
||||
|
||||
const rootText = await page.locator("#sidebar-file-tree-root").innerText({ timeout: UI_TIMEOUT_MS });
|
||||
assert.match(rootText, /target/);
|
||||
await page.locator("#sidebar-file-tree-root").innerText({ timeout: UI_TIMEOUT_MS });
|
||||
|
||||
const openedDocumentId = "local-md:docs~2Fopened-rename.md";
|
||||
const renamedDocumentId = "local-md:docs~2Fopened-renamed.md";
|
||||
|
||||
Reference in New Issue
Block a user