Skip to content

Commit 0aef1d7

Browse files
committed
test(mainview): cover sections 7-10 of the control-bar TODO
Adds: - "7. Sidebar drag in design mode" — 1:1 grow tracking, CSS cap at calc(100vw - 230px) enforced even when dragging to the right edge, no ResizeObserver loop warnings during a capped drag, drag-to-collapse still works (CCB toggle remains to re-open), panelResizeStart/Update/End forwarded to #main-toolbar so lpedit-helper can track the drag. - "8. Window resize while in design mode" — sidebar width stable across 20 synthetic resize events, main-toolbar stays flush with the window right edge, sidebar-hidden toolbar fills window - CCB. - "9. Plugin toolbar resizer" — normal-mode drag of the main-toolbar left-edge handle widens the panel ~1:1. - "10. WorkspaceManager.setPluginPanelWidth" — design mode translates the requested width into a sidebar shrink (keeping toolbar flush); normal mode leaves sidebar untouched and respects the 75%/sidebar clamp. Supporting changes: - enterDesignMode() now also waits for LP visibility + sidebar data-maxsize "1000%" so drag tests see the fully-applied collapsed layout (isInDesignMode flips before _applyCollapsedLayout runs when LP had to be opened by the toggle). - DragTestUtils.dragFromElement now waits 320ms after mouseup for the Resizer's .resizing-container shield to be removed; without this, the next test's mousedown landed on the stale shield and silently no-oped. - ResizeObserver-warning console.error spy installed via beforeEach/afterEach instead of inline try/finally so Jasmine itself guarantees the restore. - Replace awaitsFor(() => true, "a tick") placeholders with awaits(0) for event-loop flushes.
1 parent a5ca365 commit 0aef1d7

2 files changed

Lines changed: 265 additions & 2 deletions

File tree

test/spec/CentralControlBar-integ-test.js

Lines changed: 259 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*
1919
*/
2020

21-
/*global describe, it, expect, beforeAll, afterAll, beforeEach, afterEach, awaitsFor */
21+
/*global describe, it, expect, beforeAll, afterAll, beforeEach, afterEach, awaitsFor, awaits */
2222

2323
define(function (require, exports, module) {
2424

@@ -115,6 +115,16 @@ define(function (require, exports, module) {
115115
CommandManager.execute(Commands.VIEW_TOGGLE_DESIGN_MODE);
116116
await awaitsFor(function () { return WorkspaceManager.isInDesignMode(); },
117117
"design mode to activate", 10000);
118+
// isInDesignMode() flips as soon as the body class is added, but when LP
119+
// wasn't already open the toggle re-enters through a pending LP-open
120+
// promise and only runs _applyCollapsedLayout (which sets sidebar
121+
// data-maxsize to "1000%") after that resolves. Wait for LP to be visible
122+
// AND the collapsed layout to have been applied so subsequent drag tests
123+
// see the fully-settled design-mode geometry.
124+
await awaitsFor(function () {
125+
const p = livePanel();
126+
return p && p.isVisible() && _$("#sidebar").data("maxsize") === "1000%";
127+
}, "design-mode layout to be applied", 10000);
118128
}
119129

120130
async function exitDesignMode() {
@@ -440,7 +450,7 @@ define(function (require, exports, module) {
440450
for (let i = 0; i < 10; i++) {
441451
testWindow.dispatchEvent(new testWindow.Event("resize"));
442452
}
443-
await awaitsFor(function () { return true; }, "a tick", 100);
453+
await awaits(0);
444454

445455
// The sidebar is pinned — Resizer.updateResizeLimits shouldn't shrink it.
446456
expect(_$("#sidebar")[0].offsetWidth).toBe(startWidth);
@@ -571,5 +581,252 @@ define(function (require, exports, module) {
571581
expect(Math.abs(toolbarW - iconsW)).toBeLessThan(3);
572582
});
573583
});
584+
585+
describe("7. Sidebar drag in design mode", function () {
586+
// Capture all console.error messages emitted during each test so the
587+
// ResizeObserver-warning test can assert on them. Installed/removed via
588+
// beforeEach/afterEach so Jasmine itself guarantees the restore — the
589+
// spy can't leak into later tests even if a drag helper throws or an
590+
// expect() fails mid-test.
591+
let consoleErrors;
592+
let origConsoleError;
593+
594+
beforeEach(async function () {
595+
SidebarView.resize(200);
596+
await awaitsFor(function () { return _$("#sidebar")[0].offsetWidth === 200; },
597+
"sidebar to settle at baseline 200px", 2000);
598+
await enterDesignMode();
599+
600+
consoleErrors = [];
601+
origConsoleError = testWindow.console.error;
602+
testWindow.console.error = function () {
603+
consoleErrors.push(Array.prototype.slice.call(arguments).map(String).join(" "));
604+
return origConsoleError.apply(testWindow.console, arguments);
605+
};
606+
});
607+
608+
afterEach(function () {
609+
testWindow.console.error = origConsoleError;
610+
consoleErrors = null;
611+
origConsoleError = null;
612+
});
613+
614+
it("should grow the sidebar roughly 1:1 with the drag delta up to the CSS cap", async function () {
615+
const beforeWidth = _$("#sidebar")[0].offsetWidth;
616+
const $resizer = _$("#sidebar > .horz-resizer");
617+
const rect = $resizer[0].getBoundingClientRect();
618+
const handleY = rect.top + rect.height / 2;
619+
const dragDelta = 150;
620+
621+
await DragTestUtils.dragFromElement($resizer[0],
622+
rect.left + rect.width / 2 + dragDelta, handleY, testWindow);
623+
624+
const afterWidth = _$("#sidebar")[0].offsetWidth;
625+
// 1:1 tracking up to the cap — tolerate a handful of pixels for
626+
// sub-pixel accumulation across steps.
627+
expect(Math.abs((afterWidth - beforeWidth) - dragDelta)).toBeLessThan(10);
628+
});
629+
630+
it("should cap the rendered sidebar at calc(100vw - 230px) even when dragged far past it", async function () {
631+
const $resizer = _$("#sidebar > .horz-resizer");
632+
const rect = $resizer[0].getBoundingClientRect();
633+
const handleY = rect.top + rect.height / 2;
634+
const cap = testWindow.innerWidth - 230;
635+
636+
// Drag well past the cap — final mouse position near the right edge.
637+
await DragTestUtils.dragFromElement($resizer[0],
638+
testWindow.innerWidth - 10, handleY, testWindow);
639+
640+
const rendered = _$("#sidebar")[0].offsetWidth;
641+
// Rendered width hits the cap but never crosses it.
642+
expect(rendered).toBeLessThanOrEqual(cap + 1);
643+
expect(rendered).toBeGreaterThan(cap - 20);
644+
});
645+
646+
it("should not emit ResizeObserver loop warnings during a capped drag", async function () {
647+
const $resizer = _$("#sidebar > .horz-resizer");
648+
const rect = $resizer[0].getBoundingClientRect();
649+
const handleY = rect.top + rect.height / 2;
650+
await DragTestUtils.dragFromElement($resizer[0],
651+
testWindow.innerWidth - 10, handleY, testWindow, 16);
652+
653+
const resizeObserverWarnings = consoleErrors.filter(function (msg) {
654+
return /ResizeObserver/i.test(msg);
655+
});
656+
expect(resizeObserverWarnings).toEqual([]);
657+
});
658+
659+
it("should let the user collapse the sidebar via drag in design mode (CCB toggle remains to re-open)", async function () {
660+
// Drag all the way left past the sidebar's own left edge.
661+
const $resizer = _$("#sidebar > .horz-resizer");
662+
const rect = $resizer[0].getBoundingClientRect();
663+
const handleY = rect.top + rect.height / 2;
664+
const sidebarLeft = _$("#sidebar")[0].getBoundingClientRect().left;
665+
666+
await DragTestUtils.dragFromElement($resizer[0], sidebarLeft - 100, handleY, testWindow);
667+
668+
// Design mode honours the same collapse-via-drag affordance as normal
669+
// mode (see "1. Layout"). The CCB sidebar-toggle stays put so the user
670+
// can bring the sidebar back.
671+
expect(SidebarView.isVisible()).toBe(false);
672+
expect(_$("#ccbSidebarToggleBtn").is(":visible")).toBe(true);
673+
});
674+
675+
it("should forward panelResizeStart / panelResizeUpdate / panelResizeEnd from the sidebar drag to #main-toolbar", async function () {
676+
const events = [];
677+
const $mt = _$("#main-toolbar");
678+
const record = function (e) { events.push(e.type); };
679+
$mt.on("panelResizeStart.test panelResizeUpdate.test panelResizeEnd.test", record);
680+
681+
try {
682+
const $resizer = _$("#sidebar > .horz-resizer");
683+
const rect = $resizer[0].getBoundingClientRect();
684+
const handleY = rect.top + rect.height / 2;
685+
await DragTestUtils.dragFromElement($resizer[0],
686+
rect.left + 100, handleY, testWindow);
687+
// Wait for the forwarded end event — it travels through CCB's
688+
// `panelResizeEnd` handler which may still be in-flight when the
689+
// drag helper returns.
690+
await awaitsFor(function () { return events.indexOf("panelResizeEnd") !== -1; },
691+
"panelResizeEnd to be forwarded to #main-toolbar", 2000);
692+
} finally {
693+
$mt.off(".test");
694+
}
695+
696+
// All three lifecycle events must fire on #main-toolbar so downstream
697+
// listeners (lpedit-helper media-query ruler) can track the drag.
698+
expect(events).toContain("panelResizeStart");
699+
expect(events).toContain("panelResizeUpdate");
700+
expect(events).toContain("panelResizeEnd");
701+
});
702+
});
703+
704+
describe("8. Window resize while in design mode", function () {
705+
706+
beforeEach(async function () {
707+
SidebarView.resize(200);
708+
await awaitsFor(function () { return _$("#sidebar")[0].offsetWidth === 200; },
709+
"sidebar to settle at baseline 200px", 2000);
710+
await enterDesignMode();
711+
});
712+
713+
it("should keep sidebar width stable across a burst of 20 synthetic window resizes", async function () {
714+
const startWidth = _$("#sidebar")[0].offsetWidth;
715+
for (let i = 0; i < 20; i++) {
716+
testWindow.dispatchEvent(new testWindow.Event("resize"));
717+
}
718+
// Let any deferred handlers flush.
719+
await awaits(0);
720+
expect(_$("#sidebar")[0].offsetWidth).toBe(startWidth);
721+
});
722+
723+
it("should keep #main-toolbar flush with the right edge of the window after resize bursts", async function () {
724+
for (let i = 0; i < 10; i++) {
725+
testWindow.dispatchEvent(new testWindow.Event("resize"));
726+
}
727+
await awaits(0);
728+
729+
const mtRect = _$("#main-toolbar")[0].getBoundingClientRect();
730+
expect(Math.abs(mtRect.right - testWindow.innerWidth)).toBeLessThan(2);
731+
});
732+
733+
it("should give #main-toolbar the full (window - CCB) width when sidebar is hidden", async function () {
734+
SidebarView.hide();
735+
await awaitsFor(function () { return !SidebarView.isVisible(); },
736+
"sidebar to hide", 2000);
737+
738+
// Force a relayout pass by firing a resize so the collapsed-layout
739+
// reassertion runs against the new sidebar-hidden geometry.
740+
testWindow.dispatchEvent(new testWindow.Event("resize"));
741+
await awaits(0);
742+
743+
const mtW = _$("#main-toolbar").outerWidth();
744+
const expected = testWindow.innerWidth - CCB_WIDTH;
745+
// No ~70–300px phantom gap from earlier WSM clamping bugs.
746+
expect(Math.abs(mtW - expected)).toBeLessThan(5);
747+
});
748+
});
749+
750+
describe("9. Plugin toolbar resizer", function () {
751+
752+
it("should let the user drag the main-toolbar's left-edge handle to resize the panel in normal mode", async function () {
753+
await openLivePreview();
754+
// Reset to a predictable modest width before the drag so the assertion
755+
// isn't sitting at the 75% clamp from whatever previous test left.
756+
const iconsW = _$("#plugin-icons-bar").outerWidth();
757+
const startTarget = 300;
758+
WorkspaceManager.setPluginPanelWidth(startTarget - iconsW);
759+
await awaitsFor(function () {
760+
return Math.abs(_$("#main-toolbar").outerWidth() - startTarget) < 3;
761+
}, "main-toolbar to settle at 300px", 3000);
762+
763+
const beforeWidth = _$("#main-toolbar").outerWidth();
764+
const resizer = _$("#main-toolbar > .horz-resizer")[0];
765+
const rect = resizer.getBoundingClientRect();
766+
const handleY = rect.top + rect.height / 2;
767+
const delta = 120;
768+
769+
// Drag leftward to widen the toolbar by ~delta.
770+
await DragTestUtils.dragFromElement(resizer,
771+
rect.left + rect.width / 2 - delta, handleY, testWindow);
772+
773+
const afterWidth = _$("#main-toolbar").outerWidth();
774+
expect(afterWidth).toBeGreaterThan(beforeWidth);
775+
expect(Math.abs((afterWidth - beforeWidth) - delta)).toBeLessThan(20);
776+
});
777+
});
778+
779+
describe("10. WorkspaceManager.setPluginPanelWidth", function () {
780+
781+
beforeEach(async function () {
782+
SidebarView.resize(200);
783+
await awaitsFor(function () { return _$("#sidebar")[0].offsetWidth === 200; },
784+
"sidebar to settle at baseline 200px", 2000);
785+
});
786+
787+
it("should, in design mode, translate a requested plugin-panel width into a sidebar width so the layout fits", async function () {
788+
await enterDesignMode();
789+
790+
const iconsW = _$("#plugin-icons-bar").outerWidth();
791+
const requested = 400;
792+
WorkspaceManager.setPluginPanelWidth(requested);
793+
await awaits(0);
794+
795+
// Expected sidebar = window - (requested + iconsBar) - CCB, clamped at 0.
796+
const expectedSidebar = Math.max(0,
797+
testWindow.innerWidth - (requested + iconsW) - CCB_WIDTH);
798+
expect(Math.abs(_$("#sidebar")[0].offsetWidth - expectedSidebar)).toBeLessThan(3);
799+
800+
// And the main-toolbar takes the remaining right-hand room.
801+
const mtRect = _$("#main-toolbar")[0].getBoundingClientRect();
802+
expect(Math.abs(mtRect.right - testWindow.innerWidth)).toBeLessThan(2);
803+
});
804+
805+
it("should, in normal mode, resize only the plugin-panel (sidebar untouched) and respect the 75%/sidebar clamp", async function () {
806+
await openLivePreview();
807+
const iconsW = _$("#plugin-icons-bar").outerWidth();
808+
const sidebarBefore = _$("#sidebar")[0].offsetWidth;
809+
810+
// Request a very wide panel — should be clamped against 75% window
811+
// and (window - sidebar - 100). Either way sidebar must stay put.
812+
const requested = testWindow.innerWidth; // intentionally over-large
813+
WorkspaceManager.setPluginPanelWidth(requested);
814+
await awaits(0);
815+
816+
expect(_$("#sidebar")[0].offsetWidth).toBe(sidebarBefore);
817+
818+
const toolbar = _$("#main-toolbar").outerWidth();
819+
const maxAllowed = Math.min(
820+
testWindow.innerWidth * 0.75,
821+
testWindow.innerWidth - sidebarBefore - 100
822+
);
823+
// Toolbar must honour the clamp (+iconsBar = the WSM math).
824+
expect(toolbar).toBeLessThanOrEqual(maxAllowed + 3);
825+
// And at minimum it's the icons-bar + LP's minWidth.
826+
const lp = livePanel();
827+
const minToolbar = (lp && lp.minWidth ? lp.minWidth : 0) + iconsW;
828+
expect(toolbar).toBeGreaterThanOrEqual(minToolbar);
829+
});
830+
});
574831
});
575832
});

test/spec/DragTestUtils.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ define(function (require, exports, module) {
104104

105105
_fireMouse(doc, "mouseup", endX, endY, testWindow, 0);
106106
await _awaitFrames(testWindow, 2);
107+
// Resizer leaves a full-viewport `.resizing-container` shield in the DOM
108+
// for 300ms after mouseup (so a trailing mousedown still registers as a
109+
// double-click). If the next test fires its mousedown before that shield
110+
// is removed, it lands on the shield rather than the handle and the drag
111+
// silently no-ops. Waiting the shield out makes consecutive drags reliable.
112+
await new Promise(function (resolve) { testWindow.setTimeout(resolve, 320); });
107113
}
108114

109115
exports.dragFromElement = dragFromElement;

0 commit comments

Comments
 (0)