Skip to content

Commit be410ef

Browse files
committed
test(mdviewer): improve test reliability and cleanup unused helpers
Add __getCurrentContent bridge helper for verifying CM↔viewer content sync. Update _waitForMdPreviewReady to take mandatory editor arg and verify exact content match. Remove unused _openFreshMdFile, _cleanupTempFiles, and _tempFileCounter. Use doc2/doc3 fixture files with pre-existing links for link popover tests. Add Remove Link to doc3.md fixture.
1 parent 6a68ca1 commit be410ef

5 files changed

Lines changed: 124 additions & 47 deletions

File tree

src-mdviewer/src/bridge.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ export function initBridge() {
107107

108108
// Expose helpers for test access (test iframes have no sandbox)
109109
window.__getActiveFilePath = docCache.getActiveFilePath;
110+
window.__getCurrentContent = function () {
111+
return getState().currentContent;
112+
};
110113
window.__setEditModeForTest = function (editMode) {
111114
setState({ editMode });
112115
};

test/spec/LiveDevelopment-Markdown-test-files/doc2.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ This is the second test document.
1111
## Details
1212

1313
More content in document two for testing.
14+
15+
[Test Link](https://test-link-doc2.example.com)

test/spec/LiveDevelopment-Markdown-test-files/doc3.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
Third document for LRU cache testing.
44

55
Some paragraph text here.
6+
7+
[Remove Link](https://remove-link-doc3.example.com)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Link Test
2+
3+
This is a paragraph for link testing.
4+
5+
[Edit Link](https://edit-link.example.com)
6+
7+
[Remove Link](https://remove-link.example.com)
8+
9+
Another paragraph here.

test/spec/md-editor-integ-test.js

Lines changed: 108 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -192,15 +192,31 @@ define(function (require, exports, module) {
192192
mdDoc.dispatchEvent(new Event("selectionchange"));
193193
}
194194

195-
async function _waitForMdPreviewReady() {
195+
/**
196+
* Wait for the md preview iframe to be fully ready and synced with the given editor.
197+
* Verifies: iframe visible, bridge initialized, content rendered, suppression cleared,
198+
* and the viewer's loaded markdown matches the editor's content.
199+
* @param {Object} editor - The active Editor instance whose content should be synced to the viewer.
200+
*/
201+
async function _waitForMdPreviewReady(editor) {
202+
const expectedSrc = editor ? editor._codeMirror.getValue() : null;
196203
await awaitsFor(() => {
197204
const mdIFrame = _getMdPreviewIFrame();
198205
if (!mdIFrame || mdIFrame.style.display === "none") { return false; }
199206
if (!mdIFrame.src || !mdIFrame.src.includes("mdViewer")) { return false; }
200-
// Wait for bridge to initialize (exposes test helpers)
201207
const win = mdIFrame.contentWindow;
202-
return win && typeof win.__setEditModeForTest === "function";
203-
}, "md preview to be ready with bridge initialized");
208+
if (!win || typeof win.__setEditModeForTest !== "function") { return false; }
209+
if (win.__isSuppressingContentChange && win.__isSuppressingContentChange()) { return false; }
210+
const content = mdIFrame.contentDocument && mdIFrame.contentDocument.getElementById("viewer-content");
211+
if (!content || content.children.length === 0) { return false; }
212+
if (!EditorManager.getActiveEditor()) { return false; }
213+
// Verify the viewer has synced with the editor's content
214+
if (expectedSrc) {
215+
const viewerSrc = win.__getCurrentContent && win.__getCurrentContent();
216+
if (viewerSrc !== expectedSrc) { return false; }
217+
}
218+
return true;
219+
}, "md preview synced with editor content");
204220
}
205221

206222
describe("livepreview:Markdown Editor", function () {
@@ -248,7 +264,7 @@ define(function (require, exports, module) {
248264
// Now open the test markdown file
249265
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["test-shortcuts.md"]),
250266
"open test-shortcuts.md");
251-
await _waitForMdPreviewReady();
267+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
252268
testFilePath = testFolder + "/test-shortcuts.md";
253269
}
254270
}, 30000);
@@ -291,38 +307,6 @@ define(function (require, exports, module) {
291307
}
292308
}
293309

294-
let _tempFileCounter = 0;
295-
296-
/**
297-
* Create a fresh temp .md file with clean content, open it, and wait for
298-
* the md preview to be ready. Avoids CM→iframe re-render races.
299-
*/
300-
async function _openFreshMdFile(content) {
301-
content = content || ORIGINAL_MD_CONTENT;
302-
_tempFileCounter++;
303-
const tempPath = testFolder + "/_test_temp_" + _tempFileCounter + ".md";
304-
await SpecRunnerUtils.createTextFileAsync(tempPath, content);
305-
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["_test_temp_" + _tempFileCounter + ".md"]),
306-
"open temp md file");
307-
await _waitForMdPreviewReady();
308-
// Wait for viewer to have the content rendered and settled
309-
await awaitsFor(() => {
310-
const win = _getMdIFrameWin();
311-
const mdDoc = _getMdIFrameDoc();
312-
const el = mdDoc && mdDoc.getElementById("viewer-content");
313-
return el && el.querySelector("h1, p") &&
314-
win && win.__isSuppressingContentChange && !win.__isSuppressingContentChange();
315-
}, "temp file content to render and settle");
316-
return tempPath;
317-
}
318-
319-
async function _cleanupTempFiles() {
320-
for (let i = 1; i <= _tempFileCounter; i++) {
321-
const p = testFolder + "/_test_temp_" + i + ".md";
322-
await SpecRunnerUtils.deletePathAsync(p, true);
323-
}
324-
}
325-
326310
describe("Keyboard Shortcut Forwarding", function () {
327311

328312
function _listenForShortcut(key) {
@@ -581,7 +565,7 @@ define(function (require, exports, module) {
581565
async function _openMdFileAndWaitForPreview(fileName) {
582566
await awaitsForDone(SpecRunnerUtils.openProjectFiles([fileName]),
583567
"open " + fileName);
584-
await _waitForMdPreviewReady();
568+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
585569
}
586570

587571
function _getViewerScrollTop() {
@@ -722,7 +706,7 @@ define(function (require, exports, module) {
722706
// Now open an md file in the other project
723707
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["readme.md"]),
724708
"open readme.md in other project");
725-
await _waitForMdPreviewReady();
709+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
726710

727711
// Edit mode should be preserved
728712
await _assertMdEditMode(true);
@@ -761,7 +745,7 @@ define(function (require, exports, module) {
761745
await awaitsForDone(CommandManager.execute(Commands.FILE_LIVE_FILE_PREVIEW));
762746
await awaitsFor(() => WorkspaceManager.isPanelVisible("live-preview-panel"),
763747
"live preview panel to reopen");
764-
await _waitForMdPreviewReady();
748+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
765749

766750
// Verify iframe persisted (JS variable survived)
767751
const win = _getMdIFrameWin();
@@ -936,7 +920,7 @@ define(function (require, exports, module) {
936920
async function _openMdFile(fileName) {
937921
await awaitsForDone(SpecRunnerUtils.openProjectFiles([fileName]),
938922
"open " + fileName);
939-
await _waitForMdPreviewReady();
923+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
940924
}
941925

942926
beforeAll(async function () {
@@ -1122,7 +1106,7 @@ define(function (require, exports, module) {
11221106
async function _openMdFile(fileName) {
11231107
await awaitsForDone(SpecRunnerUtils.openProjectFiles([fileName]),
11241108
"open " + fileName);
1125-
await _waitForMdPreviewReady();
1109+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
11261110
}
11271111

11281112
beforeAll(async function () {
@@ -1261,7 +1245,7 @@ define(function (require, exports, module) {
12611245
async function _openMdFile(fileName) {
12621246
await awaitsForDone(SpecRunnerUtils.openProjectFiles([fileName]),
12631247
"open " + fileName);
1264-
await _waitForMdPreviewReady();
1248+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
12651249
}
12661250

12671251
beforeAll(async function () {
@@ -1366,14 +1350,91 @@ define(function (require, exports, module) {
13661350
return content && content.textContent.includes("Remove Me");
13671351
}, "text to still exist after link removal");
13681352
}, 10000);
1353+
1354+
it("should link popover allow editing link URL in viewer and sync to CM", async function () {
1355+
await _openMdFile("doc2.md");
1356+
await _enterEditMode();
1357+
await _focusMdContent();
1358+
1359+
const mdDoc = _getMdIFrameDoc();
1360+
const content = mdDoc.getElementById("viewer-content");
1361+
const link = content.querySelector("a[href*='test-link-doc2']");
1362+
expect(link).not.toBeNull();
1363+
const range = mdDoc.createRange();
1364+
range.selectNodeContents(link);
1365+
range.collapse(true);
1366+
_getMdIFrameWin().getSelection().removeAllRanges();
1367+
_getMdIFrameWin().getSelection().addRange(range);
1368+
content.dispatchEvent(new KeyboardEvent("keyup", {
1369+
key: "ArrowRight", code: "ArrowRight", bubbles: true
1370+
}));
1371+
1372+
await awaitsFor(() => {
1373+
const popover = mdDoc.getElementById("link-popover");
1374+
return popover && popover.classList.contains("visible");
1375+
}, "link popover to appear");
1376+
1377+
// Edit via popover
1378+
const popover = mdDoc.getElementById("link-popover");
1379+
popover.querySelector(".link-popover-edit-btn").click();
1380+
popover.querySelector(".link-popover-input").value = "https://edited-popover.example.com";
1381+
popover.querySelector(".link-popover-confirm-btn").click();
1382+
1383+
await awaitsFor(() =>
1384+
content.querySelector("a[href='https://edited-popover.example.com']") !== null,
1385+
"edited URL in viewer");
1386+
1387+
// Old URL should be gone
1388+
expect(content.querySelector("a[href*='test-link-doc2']")).toBeNull();
1389+
1390+
// Force close without saving
1391+
await awaitsForDone(CommandManager.execute(Commands.FILE_CLOSE, { _forceClose: true }),
1392+
"force close doc2.md");
1393+
}, 15000);
1394+
1395+
it("should link popover allow removing link in viewer and sync to CM", async function () {
1396+
await _openMdFile("doc3.md");
1397+
await _enterEditMode();
1398+
await _focusMdContent();
1399+
1400+
const mdDoc = _getMdIFrameDoc();
1401+
const content = mdDoc.getElementById("viewer-content");
1402+
const link = content.querySelector("a[href*='remove-link-doc3']");
1403+
expect(link).not.toBeNull();
1404+
const range = mdDoc.createRange();
1405+
range.selectNodeContents(link);
1406+
range.collapse(true);
1407+
_getMdIFrameWin().getSelection().removeAllRanges();
1408+
_getMdIFrameWin().getSelection().addRange(range);
1409+
content.dispatchEvent(new KeyboardEvent("keyup", {
1410+
key: "ArrowRight", code: "ArrowRight", bubbles: true
1411+
}));
1412+
1413+
await awaitsFor(() => {
1414+
const popover = mdDoc.getElementById("link-popover");
1415+
return popover && popover.classList.contains("visible");
1416+
}, "link popover to appear");
1417+
1418+
mdDoc.getElementById("link-popover").querySelector(".link-popover-unlink-btn").click();
1419+
1420+
await awaitsFor(() =>
1421+
content.querySelector("a[href*='remove-link-doc3']") === null,
1422+
"link removed from viewer via popover");
1423+
1424+
expect(content.textContent).toContain("Remove Link");
1425+
1426+
// Force close without saving
1427+
await awaitsForDone(CommandManager.execute(Commands.FILE_CLOSE, { _forceClose: true }),
1428+
"force close doc3.md");
1429+
}, 15000);
13691430
});
13701431

13711432
describe("Empty Line Placeholder", function () {
13721433

13731434
async function _openMdFile(fileName) {
13741435
await awaitsForDone(SpecRunnerUtils.openProjectFiles([fileName]),
13751436
"open " + fileName);
1376-
await _waitForMdPreviewReady();
1437+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
13771438
}
13781439

13791440
it("should empty paragraph in edit mode show hint text", async function () {
@@ -1402,8 +1463,8 @@ define(function (require, exports, module) {
14021463
}, 10000);
14031464

14041465
it("should hint only show in edit mode not reader mode", async function () {
1405-
// Use doc3 for clean state
1406-
await _openMdFile("doc3.md");
1466+
// Use doc2 for clean state (not modified by previous tests)
1467+
await _openMdFile("doc2.md");
14071468
await _enterReaderMode();
14081469

14091470
const mdDoc = _getMdIFrameDoc();
@@ -1418,7 +1479,7 @@ define(function (require, exports, module) {
14181479
async function _openMdFile(fileName) {
14191480
await awaitsForDone(SpecRunnerUtils.openProjectFiles([fileName]),
14201481
"open " + fileName);
1421-
await _waitForMdPreviewReady();
1482+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
14221483
}
14231484

14241485
function _isSlashMenuVisible() {

0 commit comments

Comments
 (0)