mengw15 commented on code in PR #6556:
URL: https://github.com/apache/texera/pull/6556#discussion_r3610184259


##########
frontend/src/app/workspace/component/result-panel/result-panel.component.spec.ts:
##########
@@ -103,4 +113,174 @@ describe("ResultPanelComponent", () => {
     expect(component.currentOperatorId).toBeUndefined();
     expect(component.operatorTitle).toBe("");
   });
+
+  describe("visibility", () => {
+    it("openPanel sets default dimensions and notifies the resize service", () 
=> {
+      const resizeSpy = vi.spyOn(resizeService, "changePanelSize");
+
+      component.openPanel();
+
+      expect(component.height).toBe(DEFAULT_HEIGHT);
+      expect(component.width).toBe(DEFAULT_WIDTH);
+      expect(resizeSpy).toHaveBeenCalledWith(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    });
+
+    it("closePanel collapses the panel", () => {
+      component.openPanel();
+
+      component.closePanel();
+
+      expect(component.height).toBe(32.5);
+      expect(component.width).toBe(0);
+    });
+
+    it("isPanelDocked is true only when the drag position matches the return 
position", () => {
+      component.returnPosition = { x: 5, y: 7 };
+      component.dragPosition = { x: 5, y: 7 };
+      expect(component.isPanelDocked()).toBe(true);
+
+      component.dragPosition = { x: 5, y: 8 };
+      expect(component.isPanelDocked()).toBe(false);
+    });
+
+    it("clearResultPanel empties the frame configs", () => {
+      component.frameComponentConfigs.set("Result", { component: 
ResultTableFrameComponent, componentInputs: {} });
+
+      component.clearResultPanel();
+
+      expect(component.frameComponentConfigs.size).toBe(0);
+    });
+  });
+
+  describe("content frames", () => {
+    it("displayConsole registers a console frame", () => {
+      component.displayConsole("op1", true);
+
+      const config = component.frameComponentConfigs.get("Console");
+      expect(config?.component).toBe(ConsoleFrameComponent);
+      expect(config?.componentInputs).toEqual({ operatorId: "op1", 
consoleInputEnabled: true });
+    });
+
+    it("displayError registers a static error frame", () => {
+      component.displayError("op1");
+
+      const config = component.frameComponentConfigs.get("Static Error");
+      expect(config?.component).toBe(ErrorFrameComponent);
+      expect(config?.componentInputs).toEqual({ operatorId: "op1" });
+    });
+
+    it("displayResult uses the table frame when a paginated result exists", () 
=> {
+      vi.spyOn(workflowResultService, 
"getPaginatedResultService").mockReturnValue(
+        {} as unknown as ReturnType<typeof 
workflowResultService.getPaginatedResultService>
+      );
+
+      component.displayResult("op1");
+
+      
expect(component.frameComponentConfigs.get("Result")?.component).toBe(ResultTableFrameComponent);
+    });
+
+    it("displayResult uses the visualization frame when only a non-paginated 
result exists", () => {
+      vi.spyOn(workflowResultService, 
"getPaginatedResultService").mockReturnValue(undefined);
+      vi.spyOn(workflowResultService, "getResultService").mockReturnValue(
+        {} as unknown as ReturnType<typeof 
workflowResultService.getResultService>
+      );
+
+      component.displayResult("op1");
+
+      
expect(component.frameComponentConfigs.get("Result")?.component).toBe(VisualizationFrameContentComponent);
+    });
+
+    it("displayResult registers nothing when the operator has no result", () 
=> {
+      vi.spyOn(workflowResultService, 
"getPaginatedResultService").mockReturnValue(undefined);
+      vi.spyOn(workflowResultService, 
"getResultService").mockReturnValue(undefined);
+
+      component.displayResult("op1");
+
+      expect(component.frameComponentConfigs.has("Result")).toBe(false);
+    });
+  });
+
+  describe("position & resize", () => {
+    it("resetPanelPosition moves the drag position back to the return 
position", () => {
+      component.returnPosition = { x: 3, y: 9 };
+      component.dragPosition = { x: 100, y: 200 };
+
+      component.resetPanelPosition();
+
+      expect(component.dragPosition).toEqual({ x: 3, y: 9 });
+    });
+
+    it("updateReturnPosition shifts y by the height delta", () => {
+      component.returnPosition = { x: 4, y: 10 };
+
+      component.updateReturnPosition(500, 300); // y + (500 - 300)
+
+      expect(component.returnPosition).toEqual({ x: 4, y: 210 });
+    });
+
+    it("updateReturnPosition is a no-op when the new height is undefined", () 
=> {
+      component.returnPosition = { x: 4, y: 10 };
+
+      component.updateReturnPosition(500, undefined);
+
+      expect(component.returnPosition).toEqual({ x: 4, y: 10 });
+    });
+
+    it("onResize applies the new size and notifies the resize service", () => {
+      // Run the requestAnimationFrame callback synchronously so the assertion 
is deterministic.
+      // These spies patch the global `window`, so restore them locally to 
avoid leaking across tests.
+      const cancelSpy = vi.spyOn(window, 
"cancelAnimationFrame").mockImplementation(() => {});
+      const rafSpy = vi.spyOn(window, 
"requestAnimationFrame").mockImplementation(cb => {
+        cb(0);
+        return 1;
+      });
+      const resizeSpy = vi.spyOn(resizeService, "changePanelSize");
+
+      try {
+        component.onResize({ width: 900, height: 600 } as NzResizeEvent);
+
+        expect(component.width).toBe(900);
+        expect(component.height).toBe(600);
+        expect(resizeSpy).toHaveBeenCalledWith(900, 600);
+      } finally {
+        rafSpy.mockRestore();
+        cancelSpy.mockRestore();
+      }
+    });
+  });
+
+  describe("drag", () => {
+    it("handleStartDrag hides the visualization overlay when it is present", 
() => {
+      const vizEl = { style: { zIndex: 0 } };
+      component.componentOutlets = {
+        nativeElement: { querySelector: () => vizEl },
+      } as unknown as ElementRef;
+
+      component.handleStartDrag();
+
+      expect(vizEl.style.zIndex).toBe(-1);
+    });
+
+    it("handleEndDrag records the final free-drag position", () => {
+      component.componentOutlets = {
+        nativeElement: { querySelector: () => null },
+      } as unknown as ElementRef;
+      const source = { getFreeDragPosition: () => ({ x: 12, y: 34 }) };
+
+      component.handleEndDrag({ source } as unknown as CdkDragEnd);
+
+      expect(component.dragPosition).toEqual({ x: 12, y: 34 });
+    });
+  });
+
+  describe("rerenderResultPanel", () => {
+    it("does nothing while previewing a workflow version", () => {
+      component.previewWorkflowVersion = true;
+      const clearSpy = vi.spyOn(component, "clearResultPanel");
+
+      component.rerenderResultPanel();
+
+      expect(clearSpy).not.toHaveBeenCalled();
+    });

Review Comment:
   Thanks. A couple of clarifications: `registerResultClearedHandler` is 
already covered by the existing "wipes the panel and operator selection when 
results are cleared" test. The remaining `registerAutoOpenResultPanel` / 
`registerAutoRerenderResultPanel` are stream-wiring set up in `ngOnInit` and 
can only be driven through several graph/execution-state services; exercising 
them meaningfully couples the spec to those services' internals, so I've kept 
this PR focused on the directly-callable panel behaviors and left the 
auto-open/auto-rerender wiring for a separate, more integration-style 
follow-up. `rerenderResultPanel`'s own logic is exercised by the existing 
cleared-results test plus the new version-preview guard.



-- 
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]

Reply via email to