收口 MNote P0 P1 P2 审查尾项
- 归档 OnlyOffice live bridge、Page AI、mindmap、design governance 与相关 bug 条目 - 补齐 MinerU OCR 后端 runtime 合同与 smoke/test 基线 - 收口 ChatOnly/Doubao、ObjectIdentity、Page Aggregate compat 与 runtime owner 文档口径 验证: - cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1 - cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_bridge -- --test-threads=1 - git diff --check - git diff --cached --check - codegraph index . --force && codegraph status . - codegraph sync . && codegraph status .
This commit is contained in:
@@ -50,6 +50,7 @@ async function uploadLocalAsset(page, root, documentId, fileName, mimeType, byte
|
||||
const form = new FormData();
|
||||
form.append("rootUri", rootUri);
|
||||
form.append("documentId", documentId);
|
||||
form.append("uploadIntent", "editor.markdown.attach");
|
||||
form.append("kind", kind);
|
||||
form.append("file", new File([new Uint8Array(bytes)], fileName, { type: mimeType }));
|
||||
const response = await fetch("/api/local-folder/assets/upload", { method: "POST", body: form });
|
||||
@@ -137,8 +138,8 @@ async function main() {
|
||||
timeout: UI_TIMEOUT_MS,
|
||||
});
|
||||
|
||||
// ======== Test 1: docx opens in main editor tab with /onlyoffice iframe ========
|
||||
console.log("Test 1: docx opens in main editor tab with /onlyoffice iframe");
|
||||
// ======== Test 1: docx opens in main editor tab with Office reader iframe ========
|
||||
console.log("Test 1: docx opens in main editor tab with Office reader iframe");
|
||||
await page.evaluate(({ asset, documentId }) => {
|
||||
window.dispatchEvent(new CustomEvent("tree.asset.open", {
|
||||
detail: {
|
||||
@@ -171,16 +172,20 @@ async function main() {
|
||||
// docx should have badge kind "word"
|
||||
assert.equal(officeTabInfo.badgeKind, "word", `docx should have badgeKind 'word', got '${officeTabInfo.badgeKind}'`);
|
||||
assert.ok(officeTabInfo.iframeExists, "Office tab should have an iframe");
|
||||
assert.ok(officeTabInfo.iframeSrc.includes("/onlyoffice"), `iframe src should include /onlyoffice: ${officeTabInfo.iframeSrc}`);
|
||||
|
||||
// Parse iframe URL and verify required params
|
||||
const iframeUrl = new URL(officeTabInfo.iframeSrc, BASE_URL);
|
||||
assert.equal(iframeUrl.pathname, "/onlyoffice", `iframe pathname should be /onlyoffice: ${iframeUrl.pathname}`);
|
||||
assert.ok(
|
||||
iframeUrl.pathname === "/office-preview" || iframeUrl.pathname === "/onlyoffice",
|
||||
`iframe pathname should be /office-preview or /onlyoffice: ${iframeUrl.pathname}`,
|
||||
);
|
||||
|
||||
// Check that assetId is in the URL (either in query params or encoded)
|
||||
const iframeAssetId = iframeUrl.searchParams.get("assetId") || "";
|
||||
assert.ok(iframeAssetId, "iframe URL should carry assetId param");
|
||||
assert.ok(iframeUrl.searchParams.has("mode"), "iframe URL should carry mode param");
|
||||
if (iframeUrl.pathname === "/onlyoffice") {
|
||||
assert.equal(iframeUrl.searchParams.get("mode"), "view", "default /onlyoffice open should use view mode");
|
||||
}
|
||||
assert.ok(iframeUrl.searchParams.has("fileUrl"), "iframe URL should carry fileUrl param");
|
||||
|
||||
// The fileUrl for local-folder should point to /api/local-folder/files/open
|
||||
@@ -304,7 +309,7 @@ async function main() {
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
// ======== Test 4: new-window defaults to view mode ========
|
||||
console.log("Test 4: new-window opens /onlyoffice with view mode");
|
||||
console.log("Test 4: new-window opens Office reader in view mode");
|
||||
const [officePopup] = await Promise.all([
|
||||
page.waitForEvent("popup", { timeout: UI_TIMEOUT_MS }).catch(() => null),
|
||||
page.evaluate(({ asset, documentId }) => {
|
||||
@@ -324,11 +329,16 @@ async function main() {
|
||||
await officePopup.waitForLoadState("domcontentloaded", { timeout: UI_TIMEOUT_MS }).catch(() => undefined);
|
||||
const popupUrl = new URL(officePopup.url());
|
||||
console.log(` New-window URL: ${popupUrl.toString()}`);
|
||||
assert.equal(popupUrl.pathname, "/onlyoffice", `new-window pathname should be /onlyoffice: ${popupUrl.pathname}`);
|
||||
assert.ok(
|
||||
popupUrl.pathname === "/office-preview" || popupUrl.pathname === "/onlyoffice",
|
||||
`new-window pathname should be /office-preview or /onlyoffice: ${popupUrl.pathname}`,
|
||||
);
|
||||
|
||||
// new-window 是浏览器目标,不代表编辑权限;默认仍应只读
|
||||
const popupMode = popupUrl.searchParams.get("mode") || "";
|
||||
assert.equal(popupMode, "view", `new-window mode should be 'view', got '${popupMode}'`);
|
||||
if (popupUrl.pathname === "/onlyoffice") {
|
||||
assert.equal(popupMode, "view", `new-window mode should be 'view', got '${popupMode}'`);
|
||||
}
|
||||
|
||||
// Check assetId is present
|
||||
const popupAssetId = popupUrl.searchParams.get("assetId") || "";
|
||||
@@ -387,21 +397,17 @@ async function main() {
|
||||
onlyofficeUrl.searchParams.set("assetId", "test-asset-id");
|
||||
onlyofficeUrl.searchParams.set("mode", "edit");
|
||||
|
||||
const response = await page.goto(onlyofficeUrl.toString(), {
|
||||
waitUntil: "domcontentloaded",
|
||||
timeout: UI_TIMEOUT_MS,
|
||||
});
|
||||
|
||||
// Verify the page rendered
|
||||
const pageContent = await page.evaluate(() => {
|
||||
return {
|
||||
title: document.title,
|
||||
hasFrameContainer: !!document.getElementById("onlyoffice-frame"),
|
||||
hasErrorContainer: !!document.getElementById("onlyoffice-error"),
|
||||
hasScript: typeof window.__MNOTE_ONLYOFFICE_READY__ !== "undefined",
|
||||
initialConfig: typeof window.initial !== "undefined",
|
||||
};
|
||||
});
|
||||
const response = await context.request.get(onlyofficeUrl.toString(), { timeout: UI_TIMEOUT_MS });
|
||||
assert.equal(response.status(), 200, `/onlyoffice should respond 200, got ${response.status()}`);
|
||||
const onlyofficeHtml = await response.text();
|
||||
|
||||
// Verify the page rendered without executing DocEditor boot against a fake file path.
|
||||
const pageContent = {
|
||||
hasFrameContainer: onlyofficeHtml.includes('id="onlyoffice-frame"'),
|
||||
hasErrorContainer: onlyofficeHtml.includes('id="onlyoffice-error"'),
|
||||
hasScript: onlyofficeHtml.includes("window.__MNOTE_ONLYOFFICE_READY__"),
|
||||
initialConfig: onlyofficeHtml.includes("const initial ="),
|
||||
};
|
||||
console.log(` /onlyoffice page: ${JSON.stringify(pageContent)}`);
|
||||
|
||||
assert.ok(pageContent.hasFrameContainer, "/onlyoffice should have #onlyoffice-frame container");
|
||||
@@ -409,17 +415,11 @@ async function main() {
|
||||
assert.ok(pageContent.hasScript, "/onlyoffice should have runtime script");
|
||||
|
||||
// Verify the config has correct document URL and callback URL source
|
||||
const scriptContent = await page.evaluate(() => {
|
||||
const scripts = document.querySelectorAll("script");
|
||||
const relevant = Array.from(scripts).filter(s => s.textContent && s.textContent.includes("buildCallbackUrl"));
|
||||
const text = relevant.length > 0 ? relevant[0].textContent : "";
|
||||
return {
|
||||
hasCallbackUrlBuilder: text.includes("buildCallbackUrl"),
|
||||
hasResolveDocumentUrl: text.includes("resolveDocumentUrl"),
|
||||
hasProxyLogic: text.includes("/api/onlyoffice/proxy"),
|
||||
snippet: text.substring(0, 200),
|
||||
};
|
||||
});
|
||||
const scriptContent = {
|
||||
hasCallbackUrlBuilder: onlyofficeHtml.includes("buildCallbackUrl"),
|
||||
hasResolveDocumentUrl: onlyofficeHtml.includes("resolveDocumentUrl"),
|
||||
hasProxyLogic: onlyofficeHtml.includes("/api/onlyoffice/proxy"),
|
||||
};
|
||||
console.log(` Script: hasCallbackUrl=${scriptContent.hasCallbackUrlBuilder}, hasResolveDocumentUrl=${scriptContent.hasResolveDocumentUrl}`);
|
||||
|
||||
assert.ok(scriptContent.hasCallbackUrlBuilder, "OnlyOffice page should define buildCallbackUrl");
|
||||
|
||||
Reference in New Issue
Block a user