This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-7366-d80cc6e50155e0cd36cb0e72254d42068309d877
in repository https://gitbox.apache.org/repos/asf/texera.git

commit 76ab7ae41270e21939d95bb65a230a1e50a00ea9
Author: Meng Wang <[email protected]>
AuthorDate: Thu Aug 6 20:45:36 2026 -0700

    test(frontend): extend ResultPanelComponent template coverage (#7366)
    
    ### What changes were proposed in this PR?
    
    Extends `result-panel.component.spec.ts` to render the
    previously-unexercised
    half of `result-panel.component.html`. The class was already ~99%
    covered but the
    template sat at ~45% — the existing tests drive the class, not the DOM.
    Adds 7
    tests that render each template branch (`detectChanges()` +
    `By.css(...)` +
    `triggerEventHandler`):
    
    - **Docked panel** (`width > 0`) — the content renders; the header
    close, the
      in-panel close, and the reset-position button fire their handlers.
    - **Collapsed panel** (`width = 0`) — only the open button renders (the
    body is
      hidden) and it wires `openPanel()`.
    - **Title interpolation** — `operatorTitle` appended after `: ` when
    set, and the
      bare `Result Panel` when not.
    - **Tabs** — the "No results available" tab when `frameComponentConfigs`
    is empty,
    and one tab per frame (`*ngFor` + `*ngComponentOutlet`) when populated.
    - **Resize handles** — rendered while docked.
    
    This takes the template from ~45% to **52/53 lines (98%)**. No
    production code
    was changed.
    
    ### Any related issues, documentation, discussions?
    
    Closes #7364.
    
    ### How was this PR tested?
    
    `ng test --watch=false --include
    src/app/workspace/component/result-panel/result-panel.component.spec.ts`
    — the 7 new tests pass; template coverage confirmed at 52/53 lines via
    the lcov report. `eslint` and `prettier --check` clean. Failure path
    verified by breaking a new assertion (→ that test goes red) and
    restoring.
    
    Note: two pre-existing `persistence on unload` tests assert
    `localStorage.setItem` and fail only under Node 26 locally (the
    file-backed `--localstorage-file` shim behaves differently from CI's
    Node 24.10.0 localStorage); they are unrelated to this change and pass
    on CI.
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Opus 4.8 [1M context])
---
 .../result-panel/result-panel.component.spec.ts    | 90 +++++++++++++++++++++-
 1 file changed, 89 insertions(+), 1 deletion(-)

diff --git 
a/frontend/src/app/workspace/component/result-panel/result-panel.component.spec.ts
 
b/frontend/src/app/workspace/component/result-panel/result-panel.component.spec.ts
index d4998ef95c..c4236299b7 100644
--- 
a/frontend/src/app/workspace/component/result-panel/result-panel.component.spec.ts
+++ 
b/frontend/src/app/workspace/component/result-panel/result-panel.component.spec.ts
@@ -18,7 +18,7 @@
  */
 
 import { ComponentFixture, TestBed } from "@angular/core/testing";
-import { ElementRef } from "@angular/core";
+import { Component, ElementRef } from "@angular/core";
 import { CdkDragEnd } from "@angular/cdk/drag-drop";
 import { NzResizeEvent } from "ng-zorro-antd/resizable";
 
@@ -664,4 +664,92 @@ describe("ResultPanelComponent", () => {
       expect(setItemSpy).not.toHaveBeenCalledWith("result-panel-style", 
expect.anything());
     });
   });
+
+  describe("template rendering", () => {
+    // Query, assert the element is present, then dispatch the event (a real 
MouseEvent
+    // for clicks so handlers calling stopPropagation()/preventDefault() work).
+    const fire = (css: string, event: string, payload: unknown): void => {
+      const el = fixture.debugElement.query(By.css(css));
+      expect(el).toBeTruthy();
+      el.triggerEventHandler(event, payload);
+    };
+
+    it("renders the docked panel chrome and wires the close / reset actions", 
() => {
+      component.width = DEFAULT_WIDTH;
+      fixture.detectChanges();
+      const closeSpy = vi.spyOn(component, "closePanel").mockImplementation(() 
=> {});
+      const resetSpy = vi.spyOn(component, 
"resetPanelPosition").mockImplementation(() => {});
+
+      expect(fixture.debugElement.query(By.css("#content"))).toBeTruthy();
+      fire("#result-buttons li[nz-menu-item]", "click", new 
MouseEvent("click")); // header close
+      fire("#panel-button button", "click", new MouseEvent("click")); // 
reset-position
+      fire("#panel-button li[nz-menu-item]", "click", new 
MouseEvent("click")); // in-panel close
+
+      expect(closeSpy).toHaveBeenCalled();
+      expect(resetSpy).toHaveBeenCalled();
+    });
+
+    it("renders only the collapsed open button and wires openPanel when width 
is 0", () => {
+      component.width = 0;
+      fixture.detectChanges();
+      const openSpy = vi.spyOn(component, "openPanel").mockImplementation(() 
=> {});
+
+      // the panel body is hidden while collapsed
+      expect(fixture.debugElement.query(By.css("#content"))).toBeNull();
+      fire("#result-buttons li[nz-menu-item]", "click", new 
MouseEvent("click")); // the open item
+
+      expect(openSpy).toHaveBeenCalled();
+    });
+
+    it("interpolates the operator title into the panel title", () => {
+      component.width = DEFAULT_WIDTH;
+      component.operatorTitle = "My Operator";
+      fixture.detectChanges();
+
+      const title = fixture.debugElement.query(By.css("#title")).nativeElement 
as HTMLElement;
+      expect(title.textContent).toContain("Result Panel: My Operator");
+    });
+
+    it("omits the separator in the title when no operator is selected", () => {
+      component.width = DEFAULT_WIDTH;
+      component.operatorTitle = "";
+      fixture.detectChanges();
+
+      const title = fixture.debugElement.query(By.css("#title")).nativeElement 
as HTMLElement;
+      expect(title.textContent?.trim()).toBe("Result Panel");
+    });
+
+    it("shows the no-results tab when there are no frames", () => {
+      component.width = DEFAULT_WIDTH;
+      component.frameComponentConfigs.clear();
+      fixture.detectChanges();
+
+      expect((fixture.nativeElement as HTMLElement).textContent).toContain("No 
results available to display.");
+    });
+
+    it("renders a tab per frame when frames are present", () => {
+      component.width = DEFAULT_WIDTH;
+      component.frameComponentConfigs.set("Result", { component: StubFrame, 
componentInputs: {} });
+      component.frameComponentConfigs.set("Console", { component: StubFrame, 
componentInputs: {} });
+      fixture.detectChanges();
+
+      const text = (fixture.nativeElement as HTMLElement).textContent ?? "";
+      expect(text).toContain("Result");
+      expect(text).toContain("Console");
+      expect(text).not.toContain("No results available to display.");
+    });
+
+    it("renders the resize handles when the panel is docked", () => {
+      component.width = DEFAULT_WIDTH;
+      vi.spyOn(component, "isPanelDocked").mockReturnValue(true);
+      fixture.detectChanges();
+
+      
expect(fixture.debugElement.query(By.css("nz-resize-handles"))).toBeTruthy();
+    });
+  });
 });
+
+// A trivial standalone frame so *ngComponentOutlet can instantiate a tab's 
content
+// without pulling in a real result-frame component's dependency graph.
+@Component({ standalone: true, template: "" })
+class StubFrame {}

Reply via email to