Files
kandev/apps/web/lib/state/dockview-measure.test.ts
T
José Almeida 2ed65cfde3 fix(web): guard dockview measure against mid-transition sidebar width (#1288)
* fix(web): guard dockview measure against mid-transition sidebar width

The unified AppSidebar (#1165) animates its width over 300ms; the dockview
content container (a flex sibling) can be measured mid-transition at a tiny
positive width in onReady, so the default layout builds too narrow and dockview
collapses the horizontal columns into a vertical stack. measureDockviewContainer
trusted any positive parent clientWidth. Reject an implausibly-small live width
(< 50% of viewport) as a not-yet-laid-out transient and fall back to the
viewport; the resize observer then snaps to the exact size.

* fix(web): preserve live height when width guard fires; assert it
2026-06-07 12:35:29 +01:00

62 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { afterEach, describe, expect, it } from "vitest";
import type { DockviewApi } from "dockview-react";
import { measureDockviewContainer } from "./dockview-measure";
function fakeApi(width: number, height: number): DockviewApi {
return { width, height } as unknown as DockviewApi;
}
describe("measureDockviewContainer", () => {
afterEach(() => {
document.body.innerHTML = "";
});
it("uses the live container size when it is laid out", () => {
const parent = document.createElement("div");
Object.defineProperty(parent, "clientWidth", { value: 1500, configurable: true });
Object.defineProperty(parent, "clientHeight", { value: 700, configurable: true });
const dv = document.createElement("div");
dv.className = "dv-dockview";
parent.appendChild(dv);
document.body.appendChild(parent);
expect(measureDockviewContainer(fakeApi(0, 0))).toEqual({ width: 1500, height: 700 });
});
it("ignores an implausibly-narrow live width (sidebar mid-transition) but keeps the live height", () => {
// Regression (post unified-sidebar #1165): the AppSidebar is a root-layout
// flex sibling with `transition-all duration-300`, so the dockview content
// container can be measured mid-animation at a tiny positive width. Building
// the default layout at that width collapses the horizontal columns into a
// vertical stack (chat / files+changes / terminal). On desktop the sidebar
// maxes at 30vw, so content is always >= ~70vw — a sub-half-viewport read is
// definitionally a transient: fall back the width to the viewport so the
// build stays horizontal (the resize observer then snaps to the exact size).
// The animation is horizontal, so the live height is reliable and is kept.
const parent = document.createElement("div");
Object.defineProperty(parent, "clientWidth", { value: 80, configurable: true });
Object.defineProperty(parent, "clientHeight", { value: 700, configurable: true });
const dv = document.createElement("div");
dv.className = "dv-dockview";
parent.appendChild(dv);
document.body.appendChild(parent);
const result = measureDockviewContainer(fakeApi(0, 0));
expect(result.width).toBe(window.innerWidth);
expect(result.height).toBe(700);
});
it("never returns a zero size on a fresh mount (no container, api not laid out yet)", () => {
// Regression: a 0×0 measurement builds the default layout at zero width, so
// dockview collapses the horizontal columns into a vertical stack (chat /
// files+changes / terminal). Fall back to the viewport instead so the
// default builds horizontally; the resize observer then snaps it to the
// exact container size.
const { width, height } = measureDockviewContainer(fakeApi(0, 0));
expect(width).toBeGreaterThan(0);
expect(height).toBeGreaterThan(0);
expect(width).toBe(window.innerWidth);
expect(height).toBe(window.innerHeight);
});
});