fix: repair resource tab and slash menu regressions
This commit is contained in:
@@ -183,6 +183,24 @@ async function readOnlyOfficeDebug(page) {
|
||||
});
|
||||
}
|
||||
|
||||
async function assertOnlyOfficeDocumentUrlReachableFromContainer(debug) {
|
||||
const resolvedFileUrl = String(debug && debug.resolvedFileUrl || "");
|
||||
assert(resolvedFileUrl.includes("/api/onlyoffice/proxy"), `OnlyOffice resolvedFileUrl 未走 proxy:${JSON.stringify(debug)}`);
|
||||
assert(
|
||||
/^(http:\/\/host\.docker\.internal:3000|http:\/\/172\.17\.0\.1:3000)/.test(resolvedFileUrl),
|
||||
`OnlyOffice resolvedFileUrl 应使用 DocumentServer 可回源的 mnote-web 地址:${resolvedFileUrl}`,
|
||||
);
|
||||
const { execFile } = require("node:child_process");
|
||||
const { promisify } = require("node:util");
|
||||
const execFileAsync = promisify(execFile);
|
||||
const response = await execFileAsync(
|
||||
"docker",
|
||||
["exec", "mnote-onlyoffice-documentserver", "curl", "-fsSI", "--max-time", "10", resolvedFileUrl],
|
||||
{ timeout: 15_000, maxBuffer: 1024 * 1024 },
|
||||
);
|
||||
assert(/HTTP\/[0-9.]+ 200/.test(response.stdout), `DocumentServer 容器无法回源读取文档:${response.stdout}\n${response.stderr}`);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const browser = await chromium.launch({ headless: process.env.HEADFUL !== "1" });
|
||||
const context = await browser.newContext();
|
||||
@@ -217,6 +235,8 @@ async function main() {
|
||||
const firstDebug = await readOnlyOfficeDebug(popup);
|
||||
assert(firstDebug.ready, "OnlyOffice ready flag 应为 true");
|
||||
assert(firstDebug.frameCount > 0, "OnlyOffice 应创建 iframe/canvas");
|
||||
assert(firstDebug.debug && firstDebug.debug.documentUrlBase, `OnlyOffice debug 应暴露 documentUrlBase:${JSON.stringify(firstDebug)}`);
|
||||
await assertOnlyOfficeDocumentUrlReachableFromContainer(firstDebug.debug);
|
||||
assert(
|
||||
/^[0-9A-Za-z_.=-]{1,128}$/.test(firstDebug.docKey),
|
||||
`OnlyOffice document.key 不符合安全字符集或长度:${firstDebug.docKey}`,
|
||||
|
||||
@@ -78,6 +78,50 @@ async function insertMindmapThroughSlash(page) {
|
||||
});
|
||||
}
|
||||
|
||||
async function assertSlashMenuAnchorsAfterMindmap(page) {
|
||||
const editor = page.locator('.document-pane[data-pane-role="primary"] .editor-surface .ProseMirror[contenteditable="true"]').first();
|
||||
await editor.click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.keyboard.press(process.platform === "darwin" ? "Meta+End" : "Control+End");
|
||||
await page.keyboard.type("/");
|
||||
await page.getByTestId("mnote-leptos-tiptap-slash-menu").waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(
|
||||
() => document.querySelector('[data-testid="mnote-leptos-tiptap-slash-menu"]')?.getAttribute("data-mnote-slash-positioned") === "host",
|
||||
null,
|
||||
{ timeout: UI_TIMEOUT_MS },
|
||||
);
|
||||
const state = await page.evaluate(() => {
|
||||
const menu = document.querySelector('[data-testid="mnote-leptos-tiptap-slash-menu"]');
|
||||
const mindmap = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
|
||||
const menuRect = menu?.getBoundingClientRect();
|
||||
const mindmapRect = mindmap?.getBoundingClientRect();
|
||||
const pointNode = menuRect
|
||||
? document.elementFromPoint(menuRect.left + 24, menuRect.top + 24)
|
||||
: null;
|
||||
return {
|
||||
menuRect: menuRect ? { top: menuRect.top, bottom: menuRect.bottom, left: menuRect.left, right: menuRect.right } : null,
|
||||
mindmapRect: mindmapRect ? { top: mindmapRect.top, bottom: mindmapRect.bottom, left: mindmapRect.left, right: mindmapRect.right } : null,
|
||||
menuPosition: menu instanceof HTMLElement ? getComputedStyle(menu).position : "",
|
||||
menuZIndex: menu instanceof HTMLElement ? getComputedStyle(menu).zIndex : "",
|
||||
hostPositioned: menu instanceof HTMLElement ? menu.getAttribute("data-mnote-slash-positioned") || "" : "",
|
||||
hitInsideMenu: Boolean(pointNode && menu && menu.contains(pointNode)),
|
||||
viewportHeight: window.innerHeight,
|
||||
};
|
||||
});
|
||||
assert(state.menuRect, `slash 菜单应可见: ${JSON.stringify(state)}`);
|
||||
assert.equal(state.menuPosition, "fixed", `slash 菜单应由宿主定位到 viewport 层: ${JSON.stringify(state)}`);
|
||||
assert(Number(state.menuZIndex) >= 120, `slash 菜单层级应高于 mindmap/块工具: ${JSON.stringify(state)}`);
|
||||
assert(state.hitInsideMenu, `slash 菜单不应被思维导图或其它层遮挡: ${JSON.stringify(state)}`);
|
||||
assert(state.menuRect.top >= 0 && state.menuRect.bottom <= state.viewportHeight, `slash 菜单不应超出视口: ${JSON.stringify(state)}`);
|
||||
if (state.mindmapRect) {
|
||||
assert(
|
||||
state.menuRect.top > state.mindmapRect.top - 80,
|
||||
`mindmap 后输入 / 时菜单不应回退到编辑器左上固定旧位置: ${JSON.stringify(state)}`,
|
||||
);
|
||||
}
|
||||
await page.keyboard.press("Escape");
|
||||
return state;
|
||||
}
|
||||
|
||||
async function readState(page) {
|
||||
return page.evaluate(() => {
|
||||
const editorRoot = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
@@ -285,6 +329,7 @@ async function main() {
|
||||
{ timeout: UI_TIMEOUT_MS },
|
||||
);
|
||||
result.saveAfterInsert = await waitForStableEditorSave(page, networkRecords, "after-insert");
|
||||
result.slashMenuAfterMindmap = await assertSlashMenuAnchorsAfterMindmap(page);
|
||||
|
||||
result.diskAfterInsert = fs.readdirSync(pageDir).sort();
|
||||
assert(result.diskAfterInsert.includes("CleanPage.md"), `页面 Markdown 应存在: ${result.diskAfterInsert.join(",")}`);
|
||||
|
||||
@@ -154,6 +154,21 @@ async function main() {
|
||||
state: "visible",
|
||||
timeout: UI_TIMEOUT_MS,
|
||||
});
|
||||
const markdownTabState = await page.evaluate(() => {
|
||||
const pageTab = document.querySelector('[data-mnote-main-tab="page"]');
|
||||
const tab = document.querySelector('.mnote-main-tab.is-active[data-mnote-tab-kind="markdown"]');
|
||||
const badge = tab?.querySelector(".mnote-main-tab-badge");
|
||||
return {
|
||||
pageText: pageTab?.textContent || "",
|
||||
resourceText: tab?.textContent || "",
|
||||
badgeKind: tab?.getAttribute("data-mnote-tab-badge-kind") || "",
|
||||
badgeColor: badge ? getComputedStyle(badge).backgroundColor : "",
|
||||
};
|
||||
});
|
||||
assert(!/\b(description|article|notes)\b/i.test(markdownTabState.pageText), `页面 tab 不应显示 Material Symbols 文本: ${JSON.stringify(markdownTabState)}`);
|
||||
assert(!/\b(description|article|notes)\b/i.test(markdownTabState.resourceText), `Markdown tab 不应显示 Material Symbols 文本: ${JSON.stringify(markdownTabState)}`);
|
||||
assert.equal(markdownTabState.badgeKind, "code", `Markdown tab 应使用黑色 code 色块: ${JSON.stringify(markdownTabState)}`);
|
||||
assert(markdownTabState.badgeColor === "rgb(17, 17, 17)", `Markdown tab 色块应为黑色: ${JSON.stringify(markdownTabState)}`);
|
||||
const editor = page.locator('.mnote-resource-tab-panel:not([hidden]) .editor-surface .ProseMirror[contenteditable="true"]').first();
|
||||
await editor.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await editor.click({ timeout: UI_TIMEOUT_MS });
|
||||
@@ -186,6 +201,18 @@ async function main() {
|
||||
state: "visible",
|
||||
timeout: UI_TIMEOUT_MS,
|
||||
});
|
||||
const officeTabState = await page.evaluate(() => {
|
||||
const tab = document.querySelector('.mnote-main-tab.is-active[data-mnote-tab-kind="office"]');
|
||||
const badge = tab?.querySelector(".mnote-main-tab-badge");
|
||||
return {
|
||||
resourceText: tab?.textContent || "",
|
||||
badgeKind: tab?.getAttribute("data-mnote-tab-badge-kind") || "",
|
||||
badgeColor: badge ? getComputedStyle(badge).backgroundColor : "",
|
||||
};
|
||||
});
|
||||
assert(!/\b(description|article|notes)\b/i.test(officeTabState.resourceText), `Office tab 不应显示 Material Symbols 文本: ${JSON.stringify(officeTabState)}`);
|
||||
assert.equal(officeTabState.badgeKind, "word", `docx tab 应使用 word 色块: ${JSON.stringify(officeTabState)}`);
|
||||
assert(officeTabState.badgeColor === "rgb(79, 125, 243)", `docx tab 色块应与附件 word 蓝色一致: ${JSON.stringify(officeTabState)}`);
|
||||
const officeFrameSrc = await page.locator('.mnote-resource-tab-panel:not([hidden]) iframe.mnote-resource-tab-frame').first().getAttribute("src", {
|
||||
timeout: UI_TIMEOUT_MS,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user