Ma77Ball commented on code in PR #6788:
URL: https://github.com/apache/texera/pull/6788#discussion_r3633784532
##########
frontend/src/app/workspace/component/left-panel/left-panel.component.spec.ts:
##########
@@ -81,4 +103,235 @@ describe("LeftPanelComponent", () => {
// the component should switch to versions display
expect(component.currentComponent).toBe(VersionsListComponent);
}));
+
+ it("openFrame(0) collapses the panel to the docked bar", () => {
+ // simulate an already-open panel
+ component.width = 250;
+ component.height = 500;
+
+ component.openFrame(0);
+
+ expect(component.width).toBe(0);
+ expect(component.height).toBe(65);
+ expect(component.currentIndex).toBe(0);
+ expect(component.currentComponent).toBeNull();
+ expect(component.title).toBe("");
+ });
+
+ it("openFrame re-opens a collapsed panel using MIN_PANEL_WIDTH and
minPanelHeight", () => {
+ // start collapsed (width 0)
+ component.openFrame(0);
+ expect(component.width).toBe(0);
+
+ component.minPanelHeight = 333;
+ component.openFrame(1);
+
+ // the collapsed -> open branch restores default width and uses
minPanelHeight
+ expect(component.width).toBe(230);
+ expect(component.height).toBe(333);
+ expect(component.currentIndex).toBe(1);
+ expect(component.currentComponent).toBe(component.items[1].component);
+ expect(component.title).toBe("Operators");
+ });
+
+ it("openFrame preserves the current width when switching frames on an
already-open panel", () => {
+ // open the panel, then simulate a user-resized width
+ component.openFrame(1);
+ component.width = 400;
+
+ component.openFrame(3);
+
+ // width must be left untouched because the panel is already open
+ expect(component.width).toBe(400);
+ expect(component.currentIndex).toBe(3);
+ expect(component.currentComponent).toBe(component.items[3].component);
+ expect(component.title).toBe(component.items[3].title);
+ });
+
+ it("constructor falls back to the Operators frame when the saved index
points to a disabled tab", () => {
+ // index 4 (Execution History) is disabled in the mock GUI config
+ localStorage.setItem("left-panel-index", "4");
+
+ const freshFixture = TestBed.createComponent(LeftPanelComponent);
+ const fresh = freshFixture.componentInstance;
+
+ expect(fresh.currentIndex).toBe(1);
+ expect(fresh.currentComponent).toBe(fresh.items[1].component);
+
+ freshFixture.destroy();
+ });
+
+ it("onDrop reorders the tab order array in place", () => {
+ // default order is [1, 2, 3, 4, 5]
+ expect(component.order).toEqual([1, 2, 3, 4, 5]);
+
+ component.onDrop({ previousIndex: 0, currentIndex: 2 } as
CdkDragDrop<string[]>);
+
+ expect(component.order).toEqual([2, 3, 1, 4, 5]);
+ });
+
+ it("onResize applies the new dimensions through requestAnimationFrame", ()
=> {
+ const rafSpy = vi.spyOn(window,
"requestAnimationFrame").mockImplementation((cb: FrameRequestCallback): number
=> {
+ cb(0);
+ return 1;
+ });
+ const cafSpy = vi.spyOn(window,
"cancelAnimationFrame").mockImplementation(() => {});
+ try {
+ component.onResize({ width: 321, height: 654 } as NzResizeEvent);
+
+ expect(component.width).toBe(321);
+ expect(component.height).toBe(654);
+ } finally {
+ rafSpy.mockRestore();
+ cafSpy.mockRestore();
+ }
+ });
+
+ it("resetPanelPosition docks the panel back onto its return position", () =>
{
+ component.returnPosition = { x: 12, y: 34 };
+ component.dragPosition = { x: 99, y: 99 };
+ component.isDocked = false;
+
+ component.resetPanelPosition();
+
+ expect(component.dragPosition).toEqual({ x: 12, y: 34 });
+ expect(component.isDocked).toBe(true);
+ });
+
+ it("handleDragStart marks the panel as undocked", () => {
+ component.isDocked = true;
+
+ component.handleDragStart();
+
+ expect(component.isDocked).toBe(false);
+ });
+
+ it("closePanelStream collapses the panel via openFrame(0)", () => {
+ const panelService = TestBed.inject(PanelService);
+ component.openFrame(1);
+ expect(component.width).toBeGreaterThan(0);
+
+ panelService.closePanels();
+
+ expect(component.width).toBe(0);
+ expect(component.currentIndex).toBe(0);
+ expect(component.currentComponent).toBeNull();
+ });
+
+ it("resetPanelStream resets the position and re-opens the Operators frame",
() => {
+ const panelService = TestBed.inject(PanelService);
+ component.returnPosition = { x: 5, y: 6 };
+ component.dragPosition = { x: 50, y: 60 };
+ component.isDocked = false;
+
+ panelService.resetPanels();
+
+ expect(component.isDocked).toBe(true);
+ expect(component.dragPosition).toEqual({ x: 5, y: 6 });
+ expect(component.currentIndex).toBe(1);
+ expect(component.currentComponent).toBe(OperatorMenuComponent);
+ });
+
+ it("ngAfterViewInit sizes minPanelHeight/height from the top-level operator
categories", fakeAsync(() => {
+ const contentEl = component.content.nativeElement;
+ // inject two top-level category panels with a known clientHeight
+ for (let i = 0; i < 2; i++) {
+ const panel = document.createElement("nz-collapse-panel");
+ panel.classList.add("operator-group");
+ panel.setAttribute("data-depth", "0");
+ Object.defineProperty(panel, "clientHeight", { value: 100, configurable:
true });
+ contentEl.appendChild(panel);
+ }
+
+ component.ngAfterViewInit();
+ tick(); // flush the setTimeout(..., 0)
+
+ // 100 + 100 = 200 measured height, + 90 padding
+ expect(component.minPanelHeight).toBe(290);
+ expect(component.height).toBe(290);
+ }));
+
+ it("ngAfterViewInit leaves the height untouched when there are no top-level
categories", fakeAsync(() => {
+ const originalMin = component.minPanelHeight;
+ const originalHeight = component.height;
+
+ // content has no matching nz-collapse-panel[data-depth="0"] elements
+ component.ngAfterViewInit();
+ tick();
+
+ expect(component.minPanelHeight).toBe(originalMin);
+ expect(component.height).toBe(originalHeight);
+ }));
+
+ it("persists panel state to localStorage on the beforeunload host listener",
() => {
+ component.width = 111;
+ component.height = 222;
+ component.currentIndex = 2;
+
+ window.dispatchEvent(new Event("beforeunload"));
+
+ expect(localStorage.getItem("left-panel-width")).toBe("111");
+ expect(localStorage.getItem("left-panel-height")).toBe("222");
+ expect(localStorage.getItem("left-panel-index")).toBe("2");
+
expect(localStorage.getItem("left-panel-order")).toBe(String(component.order));
+ });
+
+ it("ngOnDestroy skips style persistence when the left-container element is
absent", () => {
+ localStorage.removeItem("left-panel-style");
+ const getByIdSpy = vi.spyOn(document,
"getElementById").mockReturnValue(null);
+
+ component.ngOnDestroy();
+
+ // style is only written when the container exists
+ expect(localStorage.getItem("left-panel-style")).toBeNull();
+ // the remaining keys are still persisted unconditionally
+ expect(localStorage.getItem("left-panel-width")).not.toBeNull();
+ expect(localStorage.getItem("left-panel-index")).not.toBeNull();
+
+ getByIdSpy.mockRestore();
Review Comment:
Restore the global `getElementById` spy in a `finally` so a failing
assertion cannot leak the null-returning mock into later tests.
```suggestion
try {
component.ngOnDestroy();
// style is only written when the container exists
expect(localStorage.getItem("left-panel-style")).toBeNull();
// the remaining keys are still persisted unconditionally
expect(localStorage.getItem("left-panel-width")).not.toBeNull();
expect(localStorage.getItem("left-panel-index")).not.toBeNull();
} finally {
getByIdSpy.mockRestore();
}
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]