Skip to content

Commit 71971a2

Browse files
committed
fix(mdviewer): increase content max-width to A3 sheet size, add cache tests
- Change --content-max-width from 70ch to 1100px for large screens - Add Document Cache & File Switching test suite (5 tests): file switching, scroll preservation, edit mode persistence, persistent iframe verification, project switch edit mode - Add md test project with doc1/doc2/doc3/long.md test fixtures - Add _assertMdEditMode helper for reusable edit mode checks
1 parent 3526af3 commit 71971a2

8 files changed

Lines changed: 320 additions & 7 deletions

File tree

src-mdviewer/src/styles/themes/variables.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
--font-size-content: clamp(1rem, 0.925rem + 0.25vw, 1.125rem);
1111
--line-height: 1.6;
1212
--line-height-heading: 1.25;
13-
--content-max-width: 70ch;
13+
--content-max-width: 1100px;
1414
--letter-spacing: normal;
1515

1616
/* Layout */

src-mdviewer/to-create-tests.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
- [x] Escape in edit mode sends focus back to Phoenix editor
1313
- [x] F-key shortcuts (e.g. F8 for live preview toggle) work in edit mode
1414
- [x] F-key shortcuts work in reader mode
15-
- [ ] All of the above work in both reader and edit mode
1615

1716
## Document Cache & File Switching
1817
- [ ] Switching between two MD files is instant (no re-render, DOM cached)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Document One
2+
3+
This is the first test document for cache and file switching tests.
4+
5+
## Section A
6+
7+
Paragraph A with some content for testing scroll position preservation.
8+
9+
## Section B
10+
11+
Paragraph B with more content.
12+
13+
## Section C
14+
15+
Paragraph C at the bottom of the document.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Document Two
2+
3+
This is the second test document.
4+
5+
## Features
6+
7+
- Item one
8+
- Item two
9+
- Item three
10+
11+
## Details
12+
13+
More content in document two for testing.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Document Three
2+
3+
Third document for LRU cache testing.
4+
5+
Some paragraph text here.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Long Document for Scroll Testing
2+
3+
## Section 1
4+
5+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
6+
7+
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
8+
9+
## Section 2
10+
11+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
12+
13+
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
14+
15+
![Mountain landscape](https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&h=300)
16+
17+
## Section 3
18+
19+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
20+
21+
## Code Examples
22+
23+
```javascript
24+
function fibonacci(n) {
25+
if (n <= 1) return n;
26+
return fibonacci(n - 1) + fibonacci(n - 2);
27+
}
28+
29+
console.log(fibonacci(10));
30+
```
31+
32+
```html
33+
<!DOCTYPE html>
34+
<html>
35+
<head><title>Test</title></head>
36+
<body>
37+
<h1>Hello World</h1>
38+
<p>This is a test page.</p>
39+
</body>
40+
</html>
41+
```
42+
43+
## Table Example
44+
45+
| Feature | Status | Priority |
46+
| --- | --- | --- |
47+
| Dark mode | Done | High |
48+
| Export PDF | In progress | Medium |
49+
| Mobile layout | Planned | Low |
50+
51+
## Section 4
52+
53+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
54+
55+
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
56+
57+
## Section 5
58+
59+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
60+
61+
![Ocean sunset](https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=400&h=300)
62+
63+
## Section 6
64+
65+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
66+
67+
## Section 7
68+
69+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
70+
71+
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
72+
73+
## Section 8
74+
75+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
76+
77+
## Section 9
78+
79+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
80+
81+
## Section 10 - Bottom Marker
82+
83+
This is the bottom of the long document. If you can see this, you have scrolled to the end.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head><title>Simple HTML</title></head>
4+
<body>
5+
<h1 id="testId">Simple HTML page</h1>
6+
</body>
7+
</html>

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

Lines changed: 196 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ define(function (require, exports, module) {
2525
const SpecRunnerUtils = require("spec/SpecRunnerUtils");
2626

2727
const testFolder = SpecRunnerUtils.getTestPath("/spec/LiveDevelopment-MultiBrowser-test-files");
28+
const mdTestFolder = SpecRunnerUtils.getTestPath("/spec/LiveDevelopment-Markdown-test-files");
2829

2930
let testWindow, brackets, CommandManager, Commands, EditorManager, WorkspaceManager,
3031
LiveDevMultiBrowser;
@@ -244,11 +245,14 @@ define(function (require, exports, module) {
244245
}, 30000);
245246

246247
afterAll(async function () {
247-
_setMdEditMode(false);
248-
LiveDevMultiBrowser.close();
249-
await awaitsForDone(CommandManager.execute(Commands.FILE_CLOSE_ALL, { _forceClose: true }),
250-
"closing all files");
251-
await _cleanupTempFiles().catch(() => {});
248+
// Final cleanup for the entire Markdown Editor test suite
249+
if (LiveDevMultiBrowser) {
250+
LiveDevMultiBrowser.close();
251+
}
252+
if (CommandManager) {
253+
await awaitsForDone(CommandManager.execute(Commands.FILE_CLOSE_ALL, { _forceClose: true }),
254+
"final close all files");
255+
}
252256
testWindow = null;
253257
brackets = null;
254258
CommandManager = null;
@@ -557,5 +561,192 @@ define(function (require, exports, module) {
557561
}, "link to be created");
558562
}, 10000);
559563
});
564+
565+
describe("Document Cache & File Switching", function () {
566+
567+
async function _switchToMdTestProject() {
568+
await SpecRunnerUtils.loadProjectInTestWindow(mdTestFolder);
569+
await SpecRunnerUtils.deletePathAsync(mdTestFolder + "/.phcode.json", true);
570+
}
571+
572+
async function _openMdFileAndWaitForPreview(fileName) {
573+
await awaitsForDone(SpecRunnerUtils.openProjectFiles([fileName]),
574+
"open " + fileName);
575+
await _waitForMdPreviewReady();
576+
}
577+
578+
function _getViewerScrollTop() {
579+
const mdDoc = _getMdIFrameDoc();
580+
const viewer = mdDoc && mdDoc.querySelector(".app-viewer");
581+
return viewer ? viewer.scrollTop : 0;
582+
}
583+
584+
function _setViewerScrollTop(scrollTop) {
585+
const mdDoc = _getMdIFrameDoc();
586+
const viewer = mdDoc && mdDoc.querySelector(".app-viewer");
587+
if (viewer) {
588+
viewer.scrollTop = scrollTop;
589+
}
590+
}
591+
592+
function _getViewerH1Text() {
593+
const mdDoc = _getMdIFrameDoc();
594+
const h1 = mdDoc && mdDoc.querySelector("#viewer-content h1");
595+
return h1 ? h1.textContent : "";
596+
}
597+
598+
async function _assertMdEditMode(shouldBeEditing) {
599+
await awaitsFor(() => {
600+
const mdDoc = _getMdIFrameDoc();
601+
const content = mdDoc && mdDoc.getElementById("viewer-content");
602+
if (!content) { return false; }
603+
return shouldBeEditing
604+
? content.classList.contains("editing")
605+
: !content.classList.contains("editing");
606+
}, shouldBeEditing ? "md viewer to be in edit mode" : "md viewer to be in reader mode");
607+
}
608+
609+
beforeAll(async function () {
610+
// Switch to the md test project for these tests
611+
if (testWindow) {
612+
_setMdEditMode(false);
613+
await awaitsForDone(CommandManager.execute(Commands.FILE_CLOSE_ALL, { _forceClose: true }),
614+
"close all before project switch");
615+
await _switchToMdTestProject();
616+
617+
// Start live dev
618+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["simple.html"]),
619+
"open simple.html");
620+
if (!WorkspaceManager.isPanelVisible("live-preview-panel")) {
621+
await awaitsForDone(CommandManager.execute(Commands.FILE_LIVE_FILE_PREVIEW));
622+
}
623+
LiveDevMultiBrowser.open();
624+
await awaitsFor(() => {
625+
return LiveDevMultiBrowser.status === LiveDevMultiBrowser.STATUS_ACTIVE;
626+
}, "live dev to open", 20000);
627+
}
628+
}, 30000);
629+
630+
it("should switch between MD files with viewer showing correct content", async function () {
631+
await _openMdFileAndWaitForPreview("doc1.md");
632+
await awaitsFor(() => _getViewerH1Text().includes("Document One"),
633+
"doc1 heading to appear");
634+
635+
await _openMdFileAndWaitForPreview("doc2.md");
636+
await awaitsFor(() => _getViewerH1Text().includes("Document Two"),
637+
"doc2 heading to appear");
638+
639+
// Switch back to doc1 — should show doc1 content
640+
await _openMdFileAndWaitForPreview("doc1.md");
641+
await awaitsFor(() => _getViewerH1Text().includes("Document One"),
642+
"doc1 heading to appear on switch back");
643+
}, 15000);
644+
645+
it("should preserve scroll position per-document on switch", async function () {
646+
// Open long doc, scroll down
647+
await _openMdFileAndWaitForPreview("long.md");
648+
await awaitsFor(() => _getViewerH1Text().includes("Long Document"),
649+
"long doc heading to appear");
650+
651+
_setViewerScrollTop(300);
652+
await awaitsFor(() => _getViewerScrollTop() >= 290, "scroll to apply");
653+
const scrollBefore = _getViewerScrollTop();
654+
655+
// Switch to doc2
656+
await _openMdFileAndWaitForPreview("doc2.md");
657+
await awaitsFor(() => _getViewerH1Text().includes("Document Two"),
658+
"doc2 heading to appear");
659+
660+
// Switch back to long doc — scroll should be restored
661+
await _openMdFileAndWaitForPreview("long.md");
662+
await awaitsFor(() => {
663+
const scroll = _getViewerScrollTop();
664+
return Math.abs(scroll - scrollBefore) < 50;
665+
}, "scroll position to be restored");
666+
}, 15000);
667+
668+
it("should preserve edit/reader mode globally across file switches", async function () {
669+
await _openMdFileAndWaitForPreview("doc1.md");
670+
await _enterEditMode();
671+
672+
// Switch to another md file — should still be in edit mode
673+
await _openMdFileAndWaitForPreview("doc2.md");
674+
await awaitsFor(() => _getViewerH1Text().includes("Document Two"),
675+
"doc2 heading to appear");
676+
await _assertMdEditMode(true);
677+
678+
// Switch to reader mode
679+
await _enterReaderMode();
680+
await _assertMdEditMode(false);
681+
682+
// Switch to doc1 — should still be in reader mode
683+
await _openMdFileAndWaitForPreview("doc1.md");
684+
await awaitsFor(() => _getViewerH1Text().includes("Document One"),
685+
"doc1 heading to appear");
686+
await _assertMdEditMode(false);
687+
}, 15000);
688+
689+
it("should switch MD to HTML and back reusing persistent md iframe", async function () {
690+
await _openMdFileAndWaitForPreview("doc1.md");
691+
await awaitsFor(() => _getViewerH1Text().includes("Document One"),
692+
"doc1 content to load");
693+
694+
// Set a verification code inside the md iframe to prove persistence
695+
const verificationCode = "persist_" + Date.now();
696+
_getMdIFrameWin().__test_verification = verificationCode;
697+
698+
// Switch to HTML file
699+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["simple.html"]),
700+
"open simple.html");
701+
await awaitsFor(() => {
702+
const lpFrame = testWindow.document.getElementById("panel-live-preview-frame");
703+
return lpFrame && lpFrame.src && !lpFrame.src.includes("mdViewer");
704+
}, "HTML preview to load");
705+
706+
// Switch back to md file
707+
await _openMdFileAndWaitForPreview("doc1.md");
708+
await awaitsFor(() => _getViewerH1Text().includes("Document One"),
709+
"doc1 content to load after switch back");
710+
711+
// Verify iframe was NOT reloaded — our JS variable should survive
712+
const win = _getMdIFrameWin();
713+
expect(win.__test_verification).toBe(verificationCode);
714+
}, 15000);
715+
716+
it("should preserve edit mode across project switches", async function () {
717+
await _openMdFileAndWaitForPreview("doc1.md");
718+
await _enterEditMode();
719+
720+
// Switch to a different project
721+
const otherProject = SpecRunnerUtils.getTestPath("/spec/LiveDevelopment-MultiBrowser-test-files");
722+
await SpecRunnerUtils.loadProjectInTestWindow(otherProject);
723+
724+
// Open an HTML file and start live dev in the other project
725+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["simple1.html"]),
726+
"open simple1.html in other project");
727+
LiveDevMultiBrowser.open();
728+
await awaitsFor(() => {
729+
return LiveDevMultiBrowser.status === LiveDevMultiBrowser.STATUS_ACTIVE;
730+
}, "live dev active in other project", 20000);
731+
732+
// Now open an md file in the other project
733+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["readme.md"]),
734+
"open readme.md in other project");
735+
await _waitForMdPreviewReady();
736+
737+
// Edit mode should be preserved
738+
await _assertMdEditMode(true);
739+
740+
// Switch back to the md test project
741+
await _switchToMdTestProject();
742+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["simple.html"]),
743+
"reopen simple.html");
744+
LiveDevMultiBrowser.open();
745+
await awaitsFor(() => {
746+
return LiveDevMultiBrowser.status === LiveDevMultiBrowser.STATUS_ACTIVE;
747+
}, "live dev to reopen", 20000);
748+
}, 30000);
749+
});
750+
560751
});
561752
});

0 commit comments

Comments
 (0)