fix: align local markdown conflict and title behavior

This commit is contained in:
lix-2026
2026-05-24 18:16:05 +08:00
parent 289a44acea
commit 9c4bb58257
9 changed files with 664 additions and 17 deletions
@@ -136,6 +136,26 @@ async function waitForFileContent(filePath, predicate, timeoutMs) {
return { ok: false, content: lastContent };
}
async function assertNoPrimaryConflictPanel(page, label) {
await page.waitForTimeout(1000);
const conflict = await page.evaluate(() => {
const pane = document.querySelector('.document-pane[data-pane-role="primary"]');
const panel = pane?.querySelector('[data-testid="mnote-editor-conflict-panel"]') || null;
const status = pane?.querySelector('[data-runtime-editor-status]')?.getAttribute('data-runtime-editor-status')
|| document.querySelector('[data-runtime-editor-status]')?.getAttribute('data-runtime-editor-status')
|| "";
return {
visible: panel instanceof HTMLElement && panel.offsetParent !== null,
text: panel instanceof HTMLElement ? panel.textContent || "" : "",
status,
};
});
assert(
!conflict.visible && conflict.status !== "external-change-conflict",
`${label} 不应出现文件冲突: ${JSON.stringify(conflict)}`,
);
}
async function waitForPrimaryAttachment(page, fileName) {
const link = page
.locator('.document-pane[data-pane-role="primary"] .editor-surface .ProseMirror a[href*="/api/local-folder/files/open"]', {
@@ -327,6 +347,7 @@ async function main() {
assert.equal(uploadAsset.rootRelativePath, "README/uploaded-one.md", "主编辑区上传响应应返回 page resource rootRelativePath");
assert.equal(uploadAsset.markdownRelativePath, "README/uploaded-one.md", "主编辑区上传响应应返回 markdownRelativePath");
assert.equal(uploadAsset.ownerDocumentId, "local-md:README.md", "主编辑区上传响应应返回 ownerDocumentId");
await assertNoPrimaryConflictPanel(page, "主编辑区上传附件后");
checks[checkId] = {
ok: true,
@@ -411,6 +432,7 @@ async function main() {
!fs.existsSync(wrongPath) && !fs.existsSync(wrongResourcePath),
`拖入 docs 文件夹的文件不应落在 root (${wrongPath}) 或 resourceDir (${wrongResourcePath}) 下`,
);
await assertNoPrimaryConflictPanel(page, "文件树文件夹拖入文件后");
checks[checkId] = {
ok: true,
@@ -778,19 +800,41 @@ async function main() {
// 预期:文件树显示 MyNotes.md(文件名),正文显示 Body HeadingH1 内容)
const treeShowsFileName = treeTitle && treeTitle.includes("MyNotes.md");
const bodyShowsHeading = bodyHeading && bodyHeading.includes("Body Heading");
const titleHeaderInitiallyHidden = await page.evaluate(() => {
// 托管工作区(我的空间)默认显示页头标题。
const titleHeaderInitiallyVisible = await page.evaluate(() => {
const header = document.querySelector('.document-pane[data-pane-role="primary"] .document-shell-header');
return header instanceof HTMLElement ? header.hidden || header.getAttribute("data-page-title-hidden") === "true" : false;
return header instanceof HTMLElement ? !header.hidden && header.getAttribute("data-page-title-hidden") === "false" : false;
});
await page.locator('[data-testid="wolai-page-settings-trigger"]').click({ timeout: UI_TIMEOUT_MS });
const hideTitleCheckbox = page.locator('[data-page-option-checkbox="hideTitleHeader"]').first();
await hideTitleCheckbox.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
const hideTitleCheckedBefore = await hideTitleCheckbox.isChecked();
assert.equal(hideTitleCheckedBefore, true, "本地 Markdown 应默认开启隐藏文件标题");
await hideTitleCheckbox.setChecked(false, { timeout: UI_TIMEOUT_MS });
assert.equal(hideTitleCheckedBefore, false, "托管工作区(我的空间)默认不隐藏文件标题");
await hideTitleCheckbox.setChecked(true, { timeout: UI_TIMEOUT_MS });
const optionsPath = path.join(root, ".mnote", "page-options.json");
const optionsSaved = await waitForFileContent(
const optionsHidden = await waitForFileContent(
optionsPath,
(content) => {
try {
const payload = JSON.parse(content);
return payload?.pages?.["local-md:MyNotes.md"]?.hideTitleHeader === true;
} catch {
return false;
}
},
UI_TIMEOUT_MS,
);
assert(optionsHidden.ok, `隐藏标题应持久化 hideTitleHeader=true,实际: ${optionsHidden.content}`);
await page.waitForTimeout(500);
const titleHeaderHiddenAfterCheck = await page.evaluate(() => {
const header = document.querySelector('.document-pane[data-pane-role="primary"] .document-shell-header');
return header instanceof HTMLElement ? header.hidden || header.getAttribute("data-page-title-hidden") === "true" : false;
});
assert(titleHeaderHiddenAfterCheck, "勾选隐藏标题后标题应隐藏");
await hideTitleCheckbox.setChecked(false, { timeout: UI_TIMEOUT_MS });
const optionsShown = await waitForFileContent(
optionsPath,
(content) => {
try {
@@ -802,7 +846,7 @@ async function main() {
},
UI_TIMEOUT_MS,
);
assert(optionsSaved.ok, `页面设置应持久化 hideTitleHeader=false,实际: ${optionsSaved.content}`);
assert(optionsShown.ok, `显示标题应持久化 hideTitleHeader=false,实际: ${optionsShown.content}`);
await page.waitForTimeout(500);
const titleHeaderVisibleAfterToggle = await page.evaluate(() => {
const header = document.querySelector('.document-pane[data-pane-role="primary"] .document-shell-header');
@@ -819,14 +863,15 @@ async function main() {
});
checks[checkId] = {
ok: !!(treeShowsFileName && bodyShowsHeading && titleHeaderInitiallyHidden && titleHeaderVisibleAfterToggle && titleHeaderVisibleAfterReload),
ok: !!(treeShowsFileName && bodyShowsHeading && titleHeaderInitiallyVisible && titleHeaderVisibleAfterToggle && titleHeaderVisibleAfterReload),
message: `treeTitle="${treeTitle}" bodyHeading="${bodyHeading}"`,
treeTitle,
bodyHeading,
treeShowsFileName,
bodyShowsHeading,
titleHeaderInitiallyHidden,
titleHeaderInitiallyVisible,
hideTitleCheckedBefore,
titleHeaderHiddenAfterCheck,
titleHeaderVisibleAfterToggle,
titleHeaderVisibleAfterReload,
};