semblance_backup/node_modules/react-resizable-panels/src/Panel.test.tsx
2025-08-04 09:07:59 -05:00

1084 lines
33 KiB
TypeScript

import { Root, createRoot } from "react-dom/client";
import { act } from "react-dom/test-utils";
import { ImperativePanelHandle, Panel, PanelGroup, PanelResizeHandle } from ".";
import { assert } from "./utils/assert";
import { getPanelElement } from "./utils/dom/getPanelElement";
import {
mockPanelGroupOffsetWidthAndHeight,
verifyAttribute,
verifyExpandedPanelGroupLayout,
} from "./utils/test-utils";
import { createRef } from "./vendor/react";
describe("PanelGroup", () => {
let expectedWarnings: string[] = [];
let root: Root;
let container: HTMLElement;
let uninstallMockOffsetWidthAndHeight: () => void;
function expectWarning(expectedMessage: string) {
expectedWarnings.push(expectedMessage);
}
beforeEach(() => {
// @ts-expect-error
global.IS_REACT_ACT_ENVIRONMENT = true;
uninstallMockOffsetWidthAndHeight = mockPanelGroupOffsetWidthAndHeight();
container = document.createElement("div");
document.body.appendChild(container);
expectedWarnings = [];
root = createRoot(container);
jest.spyOn(console, "warn").mockImplementation((actualMessage: string) => {
const match = expectedWarnings.findIndex((expectedMessage) => {
return actualMessage.includes(expectedMessage);
});
if (match >= 0) {
expectedWarnings.splice(match, 1);
return;
}
throw Error(`Unexpected warning: ${actualMessage}`);
});
});
afterEach(() => {
uninstallMockOffsetWidthAndHeight();
jest.clearAllMocks();
jest.resetModules();
act(() => {
root.unmount();
});
expect(expectedWarnings).toHaveLength(0);
});
describe("imperative handle API", () => {
describe("collapse and expand", () => {
let leftPanelRef = createRef<ImperativePanelHandle>();
let rightPanelRef = createRef<ImperativePanelHandle>();
let mostRecentLayout: number[] | null;
beforeEach(() => {
leftPanelRef = createRef<ImperativePanelHandle>();
rightPanelRef = createRef<ImperativePanelHandle>();
mostRecentLayout = null;
const onLayout = (layout: number[]) => {
mostRecentLayout = layout;
};
act(() => {
root.render(
<PanelGroup direction="horizontal" onLayout={onLayout}>
<Panel collapsible defaultSize={50} ref={leftPanelRef} />
<PanelResizeHandle />
<Panel collapsible defaultSize={50} ref={rightPanelRef} />
</PanelGroup>
);
});
});
it("should expand and collapse the first panel in a group", () => {
assert(mostRecentLayout, "");
verifyExpandedPanelGroupLayout(mostRecentLayout, [50, 50]);
expect(leftPanelRef.current?.isCollapsed()).toBe(false);
expect(rightPanelRef.current?.isCollapsed()).toBe(false);
act(() => {
leftPanelRef.current?.collapse();
});
expect(leftPanelRef.current?.isCollapsed()).toBe(true);
expect(rightPanelRef.current?.isCollapsed()).toBe(false);
verifyExpandedPanelGroupLayout(mostRecentLayout, [0, 100]);
act(() => {
leftPanelRef.current?.expand();
});
expect(leftPanelRef.current?.isCollapsed()).toBe(false);
expect(rightPanelRef.current?.isCollapsed()).toBe(false);
verifyExpandedPanelGroupLayout(mostRecentLayout, [50, 50]);
});
it("should expand and collapse the last panel in a group", () => {
assert(mostRecentLayout, "");
verifyExpandedPanelGroupLayout(mostRecentLayout, [50, 50]);
expect(leftPanelRef.current?.isCollapsed()).toBe(false);
expect(rightPanelRef.current?.isCollapsed()).toBe(false);
act(() => {
rightPanelRef.current?.collapse();
});
verifyExpandedPanelGroupLayout(mostRecentLayout, [100, 0]);
expect(leftPanelRef.current?.isCollapsed()).toBe(false);
expect(rightPanelRef.current?.isCollapsed()).toBe(true);
act(() => {
rightPanelRef.current?.expand();
});
verifyExpandedPanelGroupLayout(mostRecentLayout, [50, 50]);
expect(leftPanelRef.current?.isCollapsed()).toBe(false);
expect(rightPanelRef.current?.isCollapsed()).toBe(false);
});
it("should re-expand to the most recent size before collapsing", () => {
assert(mostRecentLayout, "");
verifyExpandedPanelGroupLayout(mostRecentLayout, [50, 50]);
act(() => {
leftPanelRef.current?.resize(30);
});
verifyExpandedPanelGroupLayout(mostRecentLayout, [30, 70]);
act(() => {
leftPanelRef.current?.collapse();
});
verifyExpandedPanelGroupLayout(mostRecentLayout, [0, 100]);
act(() => {
leftPanelRef.current?.expand();
});
verifyExpandedPanelGroupLayout(mostRecentLayout, [30, 70]);
});
it("should report the correct state with collapsedSizes that have many decimal places", () => {
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel
collapsedSize={3.8764385221078133}
collapsible
defaultSize={50}
minSize={15}
ref={leftPanelRef}
/>
<PanelResizeHandle />
<Panel collapsible defaultSize={50} ref={rightPanelRef} />
</PanelGroup>
);
});
act(() => {
leftPanelRef.current?.collapse();
});
expect(leftPanelRef.current?.isCollapsed()).toBe(true);
expect(leftPanelRef.current?.isExpanded()).toBe(false);
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel
collapsedSize={3.8764385221078132}
collapsible
defaultSize={50}
minSize={15}
ref={leftPanelRef}
/>
<PanelResizeHandle />
<Panel collapsible defaultSize={50} ref={rightPanelRef} />
</PanelGroup>
);
});
expect(leftPanelRef.current?.isCollapsed()).toBe(true);
expect(leftPanelRef.current?.isExpanded()).toBe(false);
act(() => {
leftPanelRef.current?.expand();
});
expect(leftPanelRef.current?.isCollapsed()).toBe(false);
expect(leftPanelRef.current?.isExpanded()).toBe(true);
});
describe("when a panel is mounted in a collapsed state", () => {
beforeEach(() => {
act(() => {
root.unmount();
});
});
it("should expand to the panel's minSize", () => {
const panelRef = createRef<ImperativePanelHandle>();
root = createRoot(container);
function renderPanelGroup() {
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel
collapsible
defaultSize={0}
minSize={5}
ref={panelRef}
/>
<PanelResizeHandle />
<Panel />
</PanelGroup>
);
});
}
// Re-render and confirmed collapsed by default
renderPanelGroup();
act(() => {
panelRef.current?.collapse();
});
expect(panelRef.current?.getSize()).toEqual(0);
// Toggling a panel should expand to the minSize (since there's no previous size to restore to)
act(() => {
panelRef.current?.expand();
});
expect(panelRef.current?.getSize()).toEqual(5);
// Collapse again
act(() => {
panelRef.current?.collapse();
});
expect(panelRef.current?.getSize()).toEqual(0);
// Toggling the panel should expand to the minSize override if one is specified
// Note this only works because the previous non-collapsed size is less than the minSize override
act(() => {
panelRef.current?.expand(15);
});
expect(panelRef.current?.getSize()).toEqual(15);
});
it("should support the (optional) default size", () => {
const panelRef = createRef<ImperativePanelHandle>();
root = createRoot(container);
function renderPanelGroup() {
act(() => {
root.render(
<PanelGroup autoSaveId="test" direction="horizontal">
<Panel
collapsible
defaultSize={0}
minSize={0}
ref={panelRef}
/>
<PanelResizeHandle />
<Panel />
</PanelGroup>
);
});
}
// Re-render and confirmed collapsed by default
renderPanelGroup();
act(() => {
panelRef.current?.collapse();
});
expect(panelRef.current?.getSize()).toEqual(0);
// In this case, toggling the panel to expanded will not change its size
act(() => {
panelRef.current?.expand();
});
expect(panelRef.current?.getSize()).toEqual(0);
// But we can override the toggle behavior by passing an explicit min size
act(() => {
panelRef.current?.expand(10);
});
expect(panelRef.current?.getSize()).toEqual(10);
// Toggling an already-expanded panel should not do anything even if we pass a default size
act(() => {
panelRef.current?.expand(15);
});
expect(panelRef.current?.getSize()).toEqual(10);
});
});
});
describe("resize", () => {
let leftPanelRef = createRef<ImperativePanelHandle>();
let middlePanelRef = createRef<ImperativePanelHandle>();
let rightPanelRef = createRef<ImperativePanelHandle>();
let mostRecentLayout: number[] | null;
beforeEach(() => {
leftPanelRef = createRef<ImperativePanelHandle>();
middlePanelRef = createRef<ImperativePanelHandle>();
rightPanelRef = createRef<ImperativePanelHandle>();
mostRecentLayout = null;
const onLayout = (layout: number[]) => {
mostRecentLayout = layout;
};
act(() => {
root.render(
<PanelGroup direction="horizontal" onLayout={onLayout}>
<Panel defaultSize={20} ref={leftPanelRef} />
<PanelResizeHandle />
<Panel defaultSize={60} ref={middlePanelRef} />
<PanelResizeHandle />
<Panel defaultSize={20} ref={rightPanelRef} />
</PanelGroup>
);
});
});
it("should resize the first panel in a group", () => {
assert(mostRecentLayout, "");
verifyExpandedPanelGroupLayout(mostRecentLayout, [20, 60, 20]);
act(() => {
leftPanelRef.current?.resize(40);
});
verifyExpandedPanelGroupLayout(mostRecentLayout, [40, 40, 20]);
});
it("should resize the middle panel in a group", () => {
assert(mostRecentLayout, "");
verifyExpandedPanelGroupLayout(mostRecentLayout, [20, 60, 20]);
act(() => {
middlePanelRef.current?.resize(40);
});
verifyExpandedPanelGroupLayout(mostRecentLayout, [20, 40, 40]);
});
it("should resize the last panel in a group", () => {
assert(mostRecentLayout, "");
verifyExpandedPanelGroupLayout(mostRecentLayout, [20, 60, 20]);
act(() => {
rightPanelRef.current?.resize(40);
});
verifyExpandedPanelGroupLayout(mostRecentLayout, [20, 40, 40]);
});
});
});
describe("invariants", () => {
beforeEach(() => {
jest.spyOn(console, "error").mockImplementation(() => {
// Noop
});
});
it("should throw if default size is less than 0 or greater than 100", () => {
expect(() => {
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel defaultSize={-1} />
</PanelGroup>
);
});
}).toThrow("Invalid layout");
expect(() => {
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel defaultSize={101} />
</PanelGroup>
);
});
}).toThrow("Invalid layout");
});
it("should throw if rendered outside of a PanelGroup", () => {
expect(() => {
act(() => {
root.render(<Panel />);
});
}).toThrow(
"Panel components must be rendered within a PanelGroup container"
);
});
});
it("should support ...rest attributes", () => {
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel data-test-name="foo" id="panel" tabIndex={123} title="bar" />
<PanelResizeHandle />
<Panel />
</PanelGroup>
);
});
const element = getPanelElement("panel", container);
assert(element, "");
expect(element.tabIndex).toBe(123);
expect(element.getAttribute("data-test-name")).toBe("foo");
expect(element.title).toBe("bar");
});
describe("constraints", () => {
it("should resize a collapsed panel if the collapsedSize prop changes", () => {
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel
id="left"
collapsedSize={10}
collapsible
defaultSize={10}
minSize={25}
/>
<PanelResizeHandle />
<Panel id="middle" />
<PanelResizeHandle />
<Panel
id="right"
collapsedSize={10}
collapsible
defaultSize={10}
minSize={25}
/>
</PanelGroup>
);
});
let leftElement = getPanelElement("left", container);
let middleElement = getPanelElement("middle", container);
let rightElement = getPanelElement("right", container);
assert(leftElement, "");
assert(middleElement, "");
assert(rightElement, "");
expect(leftElement.getAttribute("data-panel-size")).toBe("10.0");
expect(middleElement.getAttribute("data-panel-size")).toBe("80.0");
expect(rightElement.getAttribute("data-panel-size")).toBe("10.0");
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel id="left" collapsedSize={5} collapsible minSize={25} />
<PanelResizeHandle />
<Panel id="middle" />
<PanelResizeHandle />
<Panel id="right" collapsedSize={5} collapsible minSize={25} />
</PanelGroup>
);
});
expect(leftElement.getAttribute("data-panel-size")).toBe("5.0");
expect(middleElement.getAttribute("data-panel-size")).toBe("90.0");
expect(rightElement.getAttribute("data-panel-size")).toBe("5.0");
});
it("it should not expand a collapsed panel if other constraints change", () => {
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel
id="left"
collapsedSize={10}
collapsible
defaultSize={10}
minSize={25}
/>
<PanelResizeHandle />
<Panel id="middle" />
<PanelResizeHandle />
<Panel
id="right"
collapsedSize={10}
collapsible
defaultSize={10}
minSize={25}
/>
</PanelGroup>
);
});
let leftElement = getPanelElement("left", container);
let middleElement = getPanelElement("middle", container);
let rightElement = getPanelElement("right", container);
assert(leftElement, "");
assert(middleElement, "");
assert(rightElement, "");
expect(leftElement.getAttribute("data-panel-size")).toBe("10.0");
expect(middleElement.getAttribute("data-panel-size")).toBe("80.0");
expect(rightElement.getAttribute("data-panel-size")).toBe("10.0");
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel id="left" collapsedSize={10} collapsible minSize={20} />
<PanelResizeHandle />
<Panel id="middle" />
<PanelResizeHandle />
<Panel id="right" collapsedSize={10} collapsible minSize={20} />
</PanelGroup>
);
});
expect(leftElement.getAttribute("data-panel-size")).toBe("10.0");
expect(middleElement.getAttribute("data-panel-size")).toBe("80.0");
expect(rightElement.getAttribute("data-panel-size")).toBe("10.0");
});
it("should resize a panel if the minSize prop changes", () => {
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel id="left" defaultSize={15} minSize={10} />
<PanelResizeHandle />
<Panel id="middle" />
<PanelResizeHandle />
<Panel id="right" defaultSize={15} minSize={10} />
</PanelGroup>
);
});
let leftElement = getPanelElement("left", container);
let middleElement = getPanelElement("middle", container);
let rightElement = getPanelElement("right", container);
assert(leftElement, "");
assert(middleElement, "");
assert(rightElement, "");
expect(leftElement.getAttribute("data-panel-size")).toBe("15.0");
expect(middleElement.getAttribute("data-panel-size")).toBe("70.0");
expect(rightElement.getAttribute("data-panel-size")).toBe("15.0");
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel id="left" minSize={20} />
<PanelResizeHandle />
<Panel id="middle" />
<PanelResizeHandle />
<Panel id="right" minSize={20} />
</PanelGroup>
);
});
expect(leftElement.getAttribute("data-panel-size")).toBe("20.0");
expect(middleElement.getAttribute("data-panel-size")).toBe("60.0");
expect(rightElement.getAttribute("data-panel-size")).toBe("20.0");
});
it("should resize a panel if the maxSize prop changes", () => {
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel id="left" defaultSize={25} maxSize={30} />
<PanelResizeHandle />
<Panel id="middle" />
<PanelResizeHandle />
<Panel id="right" defaultSize={25} maxSize={30} />
</PanelGroup>
);
});
let leftElement = getPanelElement("left", container);
let middleElement = getPanelElement("middle", container);
let rightElement = getPanelElement("right", container);
assert(leftElement, "");
assert(middleElement, "");
assert(rightElement, "");
expect(leftElement.getAttribute("data-panel-size")).toBe("25.0");
expect(middleElement.getAttribute("data-panel-size")).toBe("50.0");
expect(rightElement.getAttribute("data-panel-size")).toBe("25.0");
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel id="left" maxSize={20} />
<PanelResizeHandle />
<Panel id="middle" />
<PanelResizeHandle />
<Panel id="right" maxSize={20} />
</PanelGroup>
);
});
expect(leftElement.getAttribute("data-panel-size")).toBe("20.0");
expect(middleElement.getAttribute("data-panel-size")).toBe("60.0");
expect(rightElement.getAttribute("data-panel-size")).toBe("20.0");
});
});
describe("callbacks", () => {
describe("onCollapse", () => {
it("should be called on mount if a panels initial size is 0", () => {
let onCollapseLeft = jest.fn();
let onCollapseRight = jest.fn();
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel collapsible defaultSize={0} onCollapse={onCollapseLeft} />
<PanelResizeHandle />
<Panel collapsible onCollapse={onCollapseRight} />
</PanelGroup>
);
});
expect(onCollapseLeft).toHaveBeenCalledTimes(1);
expect(onCollapseRight).not.toHaveBeenCalled();
});
it("should be called when a panel is collapsed", () => {
let onCollapse = jest.fn();
let panelRef = createRef<ImperativePanelHandle>();
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel collapsible onCollapse={onCollapse} ref={panelRef} />
<PanelResizeHandle />
<Panel />
</PanelGroup>
);
});
expect(onCollapse).not.toHaveBeenCalled();
act(() => {
panelRef.current?.collapse();
});
expect(onCollapse).toHaveBeenCalledTimes(1);
});
it("should be called with collapsedSizes that have many decimal places", () => {
let onCollapse = jest.fn();
let panelRef = createRef<ImperativePanelHandle>();
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel
collapsible
onCollapse={onCollapse}
collapsedSize={3.8764385221078133}
minSize={10}
ref={panelRef}
/>
<PanelResizeHandle />
<Panel />
</PanelGroup>
);
});
expect(onCollapse).not.toHaveBeenCalled();
act(() => {
panelRef.current?.collapse();
});
expect(onCollapse).toHaveBeenCalledTimes(1);
act(() => {
panelRef.current?.expand();
});
expect(onCollapse).toHaveBeenCalledTimes(1);
act(() => {
panelRef.current?.collapse();
});
expect(onCollapse).toHaveBeenCalledTimes(2);
});
});
describe("onExpand", () => {
it("should be called on mount if a collapsible panels initial size is not 0", () => {
let onExpandLeft = jest.fn();
let onExpandRight = jest.fn();
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel collapsible onExpand={onExpandLeft} />
<PanelResizeHandle />
<Panel onExpand={onExpandRight} />
</PanelGroup>
);
});
expect(onExpandLeft).toHaveBeenCalledTimes(1);
expect(onExpandRight).not.toHaveBeenCalled();
});
it("should be called when a collapsible panel is expanded", () => {
let onExpand = jest.fn();
let panelRef = createRef<ImperativePanelHandle>();
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel
collapsible
defaultSize={0}
onExpand={onExpand}
ref={panelRef}
/>
<PanelResizeHandle />
<Panel />
</PanelGroup>
);
});
expect(onExpand).not.toHaveBeenCalled();
act(() => {
panelRef.current?.resize(25);
});
expect(onExpand).toHaveBeenCalledTimes(1);
});
it("should be called with collapsedSizes that have many decimal places", () => {
let onExpand = jest.fn();
let panelRef = createRef<ImperativePanelHandle>();
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel
collapsible
collapsedSize={3.8764385221078133}
defaultSize={3.8764385221078133}
minSize={10}
onExpand={onExpand}
ref={panelRef}
/>
<PanelResizeHandle />
<Panel />
</PanelGroup>
);
});
expect(onExpand).not.toHaveBeenCalled();
act(() => {
panelRef.current?.resize(25);
});
expect(onExpand).toHaveBeenCalledTimes(1);
act(() => {
panelRef.current?.collapse();
});
expect(onExpand).toHaveBeenCalledTimes(1);
act(() => {
panelRef.current?.expand();
});
expect(onExpand).toHaveBeenCalledTimes(2);
});
});
describe("onResize", () => {
it("should be called on mount", () => {
let onResizeLeft = jest.fn();
let onResizeMiddle = jest.fn();
let onResizeRight = jest.fn();
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel id="left" onResize={onResizeLeft} order={1} />
<PanelResizeHandle />
<Panel
defaultSize={50}
id="middle"
onResize={onResizeMiddle}
order={2}
/>
<PanelResizeHandle />
<Panel id="right" onResize={onResizeRight} order={3} />
</PanelGroup>
);
});
expect(onResizeLeft).toHaveBeenCalledTimes(1);
expect(onResizeLeft).toHaveBeenCalledWith(25, undefined);
expect(onResizeMiddle).toHaveBeenCalledTimes(1);
expect(onResizeMiddle).toHaveBeenCalledWith(50, undefined);
expect(onResizeRight).toHaveBeenCalledTimes(1);
expect(onResizeRight).toHaveBeenCalledWith(25, undefined);
});
it("should be called when a panel is added or removed from the group", () => {
let onResizeLeft = jest.fn();
let onResizeMiddle = jest.fn();
let onResizeRight = jest.fn();
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel
id="middle"
key="middle"
onResize={onResizeMiddle}
order={2}
/>
</PanelGroup>
);
});
expect(onResizeLeft).not.toHaveBeenCalled();
expect(onResizeMiddle).toHaveBeenCalledWith(100, undefined);
expect(onResizeRight).not.toHaveBeenCalled();
onResizeLeft.mockReset();
onResizeMiddle.mockReset();
onResizeRight.mockReset();
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel
id="left"
key="left"
maxSize={25}
minSize={25}
onResize={onResizeLeft}
order={1}
/>
<PanelResizeHandle />
<Panel
id="middle"
key="middle"
onResize={onResizeMiddle}
order={2}
/>
<PanelResizeHandle />
<Panel
id="right"
key="right"
maxSize={25}
minSize={25}
onResize={onResizeRight}
order={3}
/>
</PanelGroup>
);
});
expect(onResizeLeft).toHaveBeenCalledTimes(1);
expect(onResizeLeft).toHaveBeenCalledWith(25, undefined);
expect(onResizeMiddle).toHaveBeenCalledTimes(1);
expect(onResizeMiddle).toHaveBeenCalledWith(50, 100);
expect(onResizeRight).toHaveBeenCalledTimes(1);
expect(onResizeRight).toHaveBeenCalledWith(25, undefined);
onResizeLeft.mockReset();
onResizeMiddle.mockReset();
onResizeRight.mockReset();
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel
id="left"
key="left"
maxSize={25}
minSize={25}
onResize={onResizeLeft}
order={1}
/>
<PanelResizeHandle />
<Panel
id="middle"
key="middle"
onResize={onResizeMiddle}
order={2}
/>
</PanelGroup>
);
});
expect(onResizeLeft).not.toHaveBeenCalled();
expect(onResizeMiddle).toHaveBeenCalledTimes(1);
expect(onResizeMiddle).toHaveBeenCalledWith(75, 50);
expect(onResizeRight).not.toHaveBeenCalled();
});
});
it("should support sizes with many decimal places", () => {
let panelRef = createRef<ImperativePanelHandle>();
let onResize = jest.fn();
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel onResize={onResize} ref={panelRef} />
<PanelResizeHandle />
<Panel />
</PanelGroup>
);
});
expect(onResize).toHaveBeenCalledTimes(1);
act(() => {
panelRef.current?.resize(3.8764385221078133);
});
expect(onResize).toHaveBeenCalledTimes(2);
// An overly-high precision change should be ignored
act(() => {
panelRef.current?.resize(3.8764385221078132);
});
expect(onResize).toHaveBeenCalledTimes(2);
});
});
describe("data attributes", () => {
it("should initialize with the correct props based attributes", () => {
act(() => {
root.render(
<PanelGroup direction="horizontal" id="test-group">
<Panel defaultSize={75} id="left-panel" />
<PanelResizeHandle />
<Panel collapsible id="right-panel" />
</PanelGroup>
);
});
const leftElement = getPanelElement("left-panel", container);
const rightElement = getPanelElement("right-panel", container);
assert(leftElement, "");
assert(rightElement, "");
verifyAttribute(leftElement, "data-panel", "");
verifyAttribute(leftElement, "data-panel-id", "left-panel");
verifyAttribute(leftElement, "data-panel-group-id", "test-group");
verifyAttribute(leftElement, "data-panel-size", "75.0");
verifyAttribute(leftElement, "data-panel-collapsible", null);
verifyAttribute(rightElement, "data-panel", "");
verifyAttribute(rightElement, "data-panel-id", "right-panel");
verifyAttribute(rightElement, "data-panel-group-id", "test-group");
verifyAttribute(rightElement, "data-panel-size", "25.0");
verifyAttribute(rightElement, "data-panel-collapsible", "true");
});
it("should update the data-panel-size attribute when the panel resizes", () => {
const leftPanelRef = createRef<ImperativePanelHandle>();
act(() => {
root.render(
<PanelGroup direction="horizontal" id="test-group">
<Panel defaultSize={75} id="left-panel" ref={leftPanelRef} />
<PanelResizeHandle />
<Panel collapsible id="right-panel" />
</PanelGroup>
);
});
const leftElement = getPanelElement("left-panel", container);
const rightElement = getPanelElement("right-panel", container);
assert(leftElement, "");
assert(rightElement, "");
verifyAttribute(leftElement, "data-panel-size", "75.0");
verifyAttribute(rightElement, "data-panel-size", "25.0");
act(() => {
leftPanelRef.current?.resize(30);
});
verifyAttribute(leftElement, "data-panel-size", "30.0");
verifyAttribute(rightElement, "data-panel-size", "70.0");
});
});
describe("a11y", () => {
it("should pass explicit id prop to DOM", () => {
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel id="explicit-id" />
</PanelGroup>
);
});
const element = container.querySelector("[data-panel]");
expect(element).not.toBeNull();
expect(element?.getAttribute("id")).toBe("explicit-id");
});
it("should not pass auto-generated id prop to DOM", () => {
act(() => {
root.render(
<PanelGroup direction="horizontal">
<Panel />
</PanelGroup>
);
});
const element = container.querySelector("[data-panel]");
expect(element).not.toBeNull();
expect(element?.getAttribute("id")).toBeNull();
});
});
describe("DEV warnings", () => {
it("should warn about server rendered panels with no default size", () => {
jest.resetModules();
jest.mock("#is-browser", () => ({ isBrowser: false }));
const { TextEncoder } = require("util");
global.TextEncoder = TextEncoder;
const { renderToStaticMarkup } = require("react-dom/server.browser");
const { act } = require("react-dom/test-utils");
const Panel = require("./Panel").Panel;
const PanelGroup = require("./PanelGroup").PanelGroup;
const PanelResizeHandle =
require("./PanelResizeHandle").PanelResizeHandle;
act(() => {
// No warning expected if default sizes provided
renderToStaticMarkup(
<PanelGroup direction="horizontal">
<Panel defaultSize={100} />
<PanelResizeHandle />
<Panel defaultSize={1_000} />
</PanelGroup>
);
});
expectWarning(
"Panel defaultSize prop recommended to avoid layout shift after server rendering"
);
act(() => {
renderToStaticMarkup(
<PanelGroup direction="horizontal">
<Panel id="one" />
</PanelGroup>
);
});
});
it("should warn if invalid sizes are specified declaratively", () => {
expectWarning("default size should not be less than 0");
act(() => {
root.render(
<PanelGroup direction="horizontal" key="collapsedSize">
<Panel defaultSize={-1} />
<PanelResizeHandle />
<Panel />
</PanelGroup>
);
});
});
});
});