feat(tree): close rust family shell cutover
This commit is contained in:
@@ -23,6 +23,8 @@ const {
|
||||
|
||||
const RUN_DIRECT_TREE_SHELL_CHECKS =
|
||||
String(process.env.MNOTE_TREE_SHELL_DIRECT_SMOKE || "").trim() === "1";
|
||||
const ALLOW_LEGACY_TREE_SHELL_IFRAME_HOST =
|
||||
String(process.env.NEXT_PUBLIC_TREE_SHELL_LEGACY_IFRAME_HOST || "").trim() === "1";
|
||||
|
||||
function buildTreeShellUrl(workspaceId, params = {}) {
|
||||
const search = new URLSearchParams({
|
||||
@@ -35,7 +37,19 @@ function buildTreeShellUrl(workspaceId, params = {}) {
|
||||
}
|
||||
|
||||
function treeHostImplementationUsesIframe(implementation) {
|
||||
return implementation === "mnote_web_iframe_proxy" || implementation === "rust_inline_compat_host";
|
||||
return (
|
||||
implementation === "mnote_web_iframe_proxy" ||
|
||||
implementation === "rust_inline_compat_host" ||
|
||||
implementation === "rust_runtime_artifact_host"
|
||||
);
|
||||
}
|
||||
|
||||
function assertDefaultHostIsDomWasm(implementation, surfaceTestId) {
|
||||
if (treeHostImplementationUsesIframe(implementation) && !ALLOW_LEGACY_TREE_SHELL_IFRAME_HOST) {
|
||||
throw new Error(
|
||||
`${surfaceTestId} 默认主路径不能再使用 legacy iframe host: ${implementation || "unknown"}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForInlineTreeShellReady(page, surfaceTestId) {
|
||||
@@ -46,16 +60,26 @@ async function waitForInlineTreeShellReady(page, surfaceTestId) {
|
||||
return false;
|
||||
}
|
||||
const implementation = host.getAttribute("data-tree-host-implementation") || "";
|
||||
if (implementation !== "mnote_web_iframe_proxy" && implementation !== "rust_inline_compat_host") {
|
||||
return true;
|
||||
if (
|
||||
implementation === "mnote_web_iframe_proxy" ||
|
||||
implementation === "rust_inline_compat_host" ||
|
||||
implementation === "rust_runtime_artifact_host"
|
||||
) {
|
||||
const iframe = host.querySelector(`[data-testid="${testId}-rust-iframe"]`);
|
||||
if (!(iframe instanceof HTMLIFrameElement) || iframe.getClientRects().length === 0) {
|
||||
return false;
|
||||
}
|
||||
const doc = iframe.contentDocument;
|
||||
const status = doc?.querySelector("#tree-shell-status")?.textContent ?? "";
|
||||
return Boolean(doc?.querySelector("#tree-shell-state")) && status.includes("就绪");
|
||||
}
|
||||
const iframe = host.querySelector(`[data-testid="${testId}-rust-iframe"]`);
|
||||
if (!(iframe instanceof HTMLIFrameElement) || iframe.getClientRects().length === 0) {
|
||||
return false;
|
||||
}
|
||||
const doc = iframe.contentDocument;
|
||||
const status = doc?.querySelector("#tree-shell-status")?.textContent ?? "";
|
||||
return Boolean(doc?.querySelector("#tree-shell-state")) && status.includes("就绪");
|
||||
const domHost = host.querySelector(`[data-testid="${testId}-dom-host"]`);
|
||||
return (
|
||||
domHost instanceof HTMLElement &&
|
||||
domHost.getClientRects().length > 0 &&
|
||||
domHost.getAttribute("data-tree-browser-bridge") === "dom_wasm" &&
|
||||
domHost.getAttribute("data-tree-dom-shell-ready") === "true"
|
||||
);
|
||||
},
|
||||
surfaceTestId,
|
||||
{ timeout: UI_TIMEOUT_MS },
|
||||
@@ -161,16 +185,27 @@ async function getPageTreeHostDriver(page) {
|
||||
return false;
|
||||
}
|
||||
const implementation = element.getAttribute("data-tree-host-implementation") || "";
|
||||
if (implementation === "mnote_web_iframe_proxy" || implementation === "rust_inline_compat_host") {
|
||||
if (
|
||||
implementation === "mnote_web_iframe_proxy" ||
|
||||
implementation === "rust_inline_compat_host" ||
|
||||
implementation === "rust_runtime_artifact_host"
|
||||
) {
|
||||
const iframe = element.querySelector('[data-testid="sidebar-page-tree-shell-rust-iframe"]');
|
||||
return iframe instanceof HTMLIFrameElement && iframe.getClientRects().length > 0;
|
||||
}
|
||||
return true;
|
||||
const domHost = element.querySelector('[data-testid="sidebar-page-tree-shell-dom-host"]');
|
||||
return (
|
||||
domHost instanceof HTMLElement &&
|
||||
domHost.getClientRects().length > 0 &&
|
||||
domHost.getAttribute("data-tree-browser-bridge") === "dom_wasm" &&
|
||||
domHost.getAttribute("data-tree-dom-shell-ready") === "true"
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{ timeout: UI_TIMEOUT_MS },
|
||||
);
|
||||
const implementation = await host.getAttribute("data-tree-host-implementation");
|
||||
assertDefaultHostIsDomWasm(implementation, "sidebar-page-tree-shell");
|
||||
if (treeHostImplementationUsesIframe(implementation)) {
|
||||
await waitForInlineTreeShellReady(page, "sidebar-page-tree-shell");
|
||||
return {
|
||||
@@ -179,7 +214,8 @@ async function getPageTreeHostDriver(page) {
|
||||
scope: page.frameLocator('[data-testid="sidebar-page-tree-shell-rust-iframe"]'),
|
||||
};
|
||||
}
|
||||
return { kind: "react", host, scope: host };
|
||||
await waitForInlineTreeShellReady(page, "sidebar-page-tree-shell");
|
||||
return { kind: "dom", host, scope: host };
|
||||
}
|
||||
|
||||
async function getFileTreeHostDriver(page) {
|
||||
@@ -192,16 +228,27 @@ async function getFileTreeHostDriver(page) {
|
||||
return false;
|
||||
}
|
||||
const implementation = element.getAttribute("data-tree-host-implementation") || "";
|
||||
if (implementation === "mnote_web_iframe_proxy" || implementation === "rust_inline_compat_host") {
|
||||
if (
|
||||
implementation === "mnote_web_iframe_proxy" ||
|
||||
implementation === "rust_inline_compat_host" ||
|
||||
implementation === "rust_runtime_artifact_host"
|
||||
) {
|
||||
const iframe = element.querySelector('[data-testid="sidebar-file-tree-shell-rust-iframe"]');
|
||||
return iframe instanceof HTMLIFrameElement && iframe.getClientRects().length > 0;
|
||||
}
|
||||
return true;
|
||||
const domHost = element.querySelector('[data-testid="sidebar-file-tree-shell-dom-host"]');
|
||||
return (
|
||||
domHost instanceof HTMLElement &&
|
||||
domHost.getClientRects().length > 0 &&
|
||||
domHost.getAttribute("data-tree-browser-bridge") === "dom_wasm" &&
|
||||
domHost.getAttribute("data-tree-dom-shell-ready") === "true"
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{ timeout: UI_TIMEOUT_MS },
|
||||
);
|
||||
const implementation = await host.getAttribute("data-tree-host-implementation");
|
||||
assertDefaultHostIsDomWasm(implementation, "sidebar-file-tree-shell");
|
||||
if (treeHostImplementationUsesIframe(implementation)) {
|
||||
await waitForInlineTreeShellReady(page, "sidebar-file-tree-shell");
|
||||
return {
|
||||
@@ -210,7 +257,8 @@ async function getFileTreeHostDriver(page) {
|
||||
scope: page.frameLocator('[data-testid="sidebar-file-tree-shell-rust-iframe"]'),
|
||||
};
|
||||
}
|
||||
return { kind: "react", host, scope: host };
|
||||
await waitForInlineTreeShellReady(page, "sidebar-file-tree-shell");
|
||||
return { kind: "dom", host, scope: host };
|
||||
}
|
||||
|
||||
async function openPageTreeDocumentFromHost(page, driver, documentId) {
|
||||
@@ -228,7 +276,7 @@ async function openPageTreeDocumentFromHost(page, driver, documentId) {
|
||||
});
|
||||
} else {
|
||||
await driver.scope
|
||||
.locator(`[data-testid="page-tree-row"][data-node-id="${documentId}"] [data-testid="page-tree-open"]`)
|
||||
.locator(`.tree-row[data-shell-mode="page"][data-node-id="${documentId}"] [data-testid="tree-node-open"]`)
|
||||
.click({ timeout: UI_TIMEOUT_MS });
|
||||
}
|
||||
const popupPage = await popupPromise;
|
||||
@@ -252,9 +300,9 @@ async function openPageTreeContextMenuFromHost(page, driver, documentId) {
|
||||
button.click();
|
||||
});
|
||||
} else {
|
||||
const row = driver.scope.locator(`[data-testid="page-tree-row"][data-node-id="${documentId}"]`);
|
||||
const row = driver.scope.locator(`.tree-row[data-shell-mode="page"][data-node-id="${documentId}"]`);
|
||||
await row.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await row.getByRole("button", { name: "更多操作" }).click({ timeout: UI_TIMEOUT_MS, force: true });
|
||||
await row.locator('[data-testid="tree-action-menu"]').click({ timeout: UI_TIMEOUT_MS, force: true });
|
||||
}
|
||||
await page.getByText("重命名", { exact: true }).waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.keyboard.press("Escape");
|
||||
@@ -270,7 +318,7 @@ async function doubleClickFileTreeDocumentFromHost(page, driver, documentId) {
|
||||
.dblclick({ timeout: UI_TIMEOUT_MS });
|
||||
} else {
|
||||
await driver.scope
|
||||
.locator(`[data-testid="filetree-doc-row"][data-doc-id="${documentId}"]`)
|
||||
.locator(`[data-testid="filetree-doc-row"][data-document-id="${documentId}"], [data-testid="filetree-doc-row"][data-doc-id="${documentId}"]`)
|
||||
.dblclick({ timeout: UI_TIMEOUT_MS });
|
||||
}
|
||||
const popupPage = await popupPromise;
|
||||
@@ -349,11 +397,11 @@ async function waitForPageTreeTitle(page, documentId, title) {
|
||||
}
|
||||
|
||||
await driver.scope
|
||||
.locator(`[data-testid="page-tree-row"][data-node-id="${documentId}"]`)
|
||||
.locator(`.tree-row[data-shell-mode="page"][data-node-id="${documentId}"]`)
|
||||
.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(
|
||||
({ nodeId, expectedTitle }) => {
|
||||
const row = document.querySelector(`[data-testid="page-tree-row"][data-node-id="${nodeId}"]`);
|
||||
const row = document.querySelector(`.tree-row[data-shell-mode="page"][data-node-id="${nodeId}"]`);
|
||||
return (row?.textContent ?? "").includes(expectedTitle);
|
||||
},
|
||||
{ nodeId: documentId, expectedTitle: title },
|
||||
@@ -387,11 +435,13 @@ async function waitForFileTreeTitle(page, documentId, title) {
|
||||
}
|
||||
|
||||
await driver.scope
|
||||
.locator(`[data-testid="filetree-doc-row"][data-doc-id="${documentId}"]`)
|
||||
.locator(`[data-testid="filetree-doc-row"][data-document-id="${documentId}"], [data-testid="filetree-doc-row"][data-doc-id="${documentId}"]`)
|
||||
.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(
|
||||
({ docId, expectedTitle }) => {
|
||||
const row = document.querySelector(`[data-testid="filetree-doc-row"][data-doc-id="${docId}"]`);
|
||||
const row = document.querySelector(
|
||||
`[data-testid="filetree-doc-row"][data-document-id="${docId}"], [data-testid="filetree-doc-row"][data-doc-id="${docId}"]`,
|
||||
);
|
||||
return (row?.textContent ?? "").includes(expectedTitle);
|
||||
},
|
||||
{ docId: documentId, expectedTitle: title },
|
||||
@@ -866,10 +916,12 @@ async function runPickerDialogChecks(context, fixture) {
|
||||
const pickerSurface = dialog.getByTestId("tree-picker-surface");
|
||||
await pickerSurface.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const searchInput = dialog.getByPlaceholder("移动到...");
|
||||
const pickerUsesIframe = (await pickerSurface.locator('[data-testid="tree-picker-surface-rust-iframe"]').count()) > 0;
|
||||
if (pickerUsesIframe) {
|
||||
await waitForInlineTreeShellReady(page, "tree-picker-surface");
|
||||
}
|
||||
await waitForInlineTreeShellReady(page, "tree-picker-surface");
|
||||
const implementation = await pickerSurface.getAttribute("data-tree-host-implementation");
|
||||
assertDefaultHostIsDomWasm(implementation, "tree-picker-surface");
|
||||
const pickerUsesIframe =
|
||||
treeHostImplementationUsesIframe(implementation) &&
|
||||
(await pickerSurface.locator('[data-testid="tree-picker-surface-rust-iframe"]').count()) > 0;
|
||||
return { dialog, pickerSurface, searchInput, pickerUsesIframe };
|
||||
};
|
||||
|
||||
@@ -987,7 +1039,7 @@ async function runPickerDialogChecks(context, fixture) {
|
||||
{ timeout: UI_TIMEOUT_MS },
|
||||
);
|
||||
} else {
|
||||
await dialog
|
||||
await keyboardDialog
|
||||
.locator(`[data-testid="tree-picker-row"][data-node-id="${fixture.targetId}"]`)
|
||||
.waitFor({
|
||||
state: "visible",
|
||||
@@ -1048,7 +1100,7 @@ async function runPickerDialogChecks(context, fixture) {
|
||||
pickerSearch: true,
|
||||
pickerEmpty: true,
|
||||
pickerSelect: true,
|
||||
pickerHostKind: keyboardUsesIframe ? "iframe" : "react",
|
||||
pickerHostKind: keyboardUsesIframe ? "iframe" : "dom",
|
||||
emptyStateText,
|
||||
pickerRootVisible,
|
||||
pickerExcludeCurrentDocument: true,
|
||||
|
||||
Reference in New Issue
Block a user