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]