You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@texera.apache.org by gi...@apache.org on 2026/07/23 00:17:22 UTC

(texera) branch gh-readonly-queue/main/pr-6785-e345e4559560d4d3daad316d88c9626f5e107b21 created (now 1a17bc7892)

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

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


      at 1a17bc7892 test(frontend): extend VersionsListComponent unit test coverage (#6785)

This branch includes the following new commits:

     new 1a17bc7892 test(frontend): extend VersionsListComponent unit test coverage (#6785)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(texera) 01/01: test(frontend): extend VersionsListComponent unit test coverage (#6785)

Posted by gi...@apache.org.
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-6785-e345e4559560d4d3daad316d88c9626f5e107b21
in repository https://gitbox.apache.org/repos/asf/texera.git

commit 1a17bc7892489011f8e1e481bbbac5d5115fb32d
Author: Xinyuan Lin <xi...@uci.edu>
AuthorDate: Wed Jul 22 17:04:15 2026 -0700

    test(frontend): extend VersionsListComponent unit test coverage (#6785)
    
    ### What changes were proposed in this PR?
    
    Extends `versions-list.component.spec.ts` (11 tests), covering the
    version load/select/revert/display flows and their error/guard branches.
    Coverage 46% -> high. No existing tests modified.
    
    ### Any related issues, documentation, discussions?
    
    Closes #6779.
    
    ### How was this PR tested?
    
    `ng test --include='**/versions-list.component.spec.ts'` -> 11/11
    passing. `yarn format:ci` passes.
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Opus 4.8 [1M context])
---
 .../versions-list/versions-list.component.spec.ts  | 162 ++++++++++++++++++++-
 1 file changed, 161 insertions(+), 1 deletion(-)

diff --git a/frontend/src/app/workspace/component/left-panel/versions-list/versions-list.component.spec.ts b/frontend/src/app/workspace/component/left-panel/versions-list/versions-list.component.spec.ts
index a449218b8f..7517e1547a 100644
--- a/frontend/src/app/workspace/component/left-panel/versions-list/versions-list.component.spec.ts
+++ b/frontend/src/app/workspace/component/left-panel/versions-list/versions-list.component.spec.ts
@@ -19,6 +19,7 @@
 
 import { ComponentFixture, TestBed } from "@angular/core/testing";
 import { WorkflowActionService } from "../../../service/workflow-graph/model/workflow-action.service";
+import { DEFAULT_WORKFLOW } from "../../../service/workflow-graph/model/workflow-action.service";
 import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
 import { FormsModule, ReactiveFormsModule } from "@angular/forms";
 import { FormlyModule } from "@ngx-formly/core";
@@ -27,11 +28,16 @@ import { HttpClientTestingModule } from "@angular/common/http/testing";
 import { VersionsListComponent } from "./versions-list.component";
 import { RouterTestingModule } from "@angular/router/testing";
 import { commonTestProviders } from "../../../../common/testing/test-utils";
+import { WorkflowVersionService } from "../../../../dashboard/service/user/workflow-version/workflow-version.service";
+import { WorkflowVersionEntry } from "../../../../dashboard/type/workflow-version-entry";
+import { Workflow } from "../../../../common/type/workflow";
+import { of } from "rxjs";
 
 describe("VersionsListComponent", () => {
   let component: VersionsListComponent;
   let fixture: ComponentFixture<VersionsListComponent>;
   let workflowActionService: WorkflowActionService;
+  let workflowVersionService: WorkflowVersionService;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
@@ -50,10 +56,164 @@ describe("VersionsListComponent", () => {
     fixture = TestBed.createComponent(VersionsListComponent);
     component = fixture.componentInstance;
     workflowActionService = TestBed.inject(WorkflowActionService);
-    fixture.detectChanges();
+    workflowVersionService = TestBed.inject(WorkflowVersionService);
+    // Intentionally do NOT call fixture.detectChanges() here: the ngOnInit specs configure
+    // their spies and then invoke ngOnInit() themselves, so this lets them observe the
+    // first/only invocation. Tests that need the rendered template call detectChanges() locally.
+  });
+
+  afterEach(() => {
+    fixture.destroy();
+    vi.restoreAllMocks();
   });
 
   it("should create", () => {
     expect(component).toBeTruthy();
   });
+
+  // Helper: build a collapsable-entry list directly on the component.
+  const makeEntry = (vId: number, importance: boolean, expand = false) => ({
+    vId,
+    creationTime: vId * 1000,
+    content: `content-${vId}`,
+    importance,
+    expand,
+  });
+
+  describe("getDisplayedVersionId", () => {
+    it("should compute the descending displayed id as count - index", () => {
+      expect(component.getDisplayedVersionId(0, 5)).toBe(5);
+      expect(component.getDisplayedVersionId(2, 5)).toBe(3);
+      expect(component.getDisplayedVersionId(4, 5)).toBe(1);
+    });
+  });
+
+  describe("collapse", () => {
+    it("should do nothing when versionsList is undefined", () => {
+      component.versionsList = undefined;
+      // must not throw when there is no list to walk
+      expect(() => component.collapse(0, true)).not.toThrow();
+      expect(component.versionsList).toBeUndefined();
+    });
+
+    it("should expand the trailing non-important entries when $event is true", () => {
+      component.versionsList = [
+        makeEntry(5, true),
+        makeEntry(4, false),
+        makeEntry(3, false),
+        makeEntry(2, true),
+        makeEntry(1, false),
+      ];
+
+      component.collapse(0, true);
+
+      // entries 1 and 2 (non-important) are expanded, then the walk stops at the
+      // next important entry (index 3); index 3 and 4 are left untouched.
+      expect(component.versionsList[1].expand).toBe(true);
+      expect(component.versionsList[2].expand).toBe(true);
+      expect(component.versionsList[3].expand).toBe(false);
+      expect(component.versionsList[4].expand).toBe(false);
+    });
+
+    it("should collapse the trailing non-important entries when $event is false", () => {
+      component.versionsList = [
+        makeEntry(5, true),
+        makeEntry(4, false, true),
+        makeEntry(3, false, true),
+        makeEntry(2, true, true),
+        makeEntry(1, false, true),
+      ];
+
+      component.collapse(0, false);
+
+      expect(component.versionsList[1].expand).toBe(false);
+      expect(component.versionsList[2].expand).toBe(false);
+      // stops at the important entry, so its expand state is preserved
+      expect(component.versionsList[3].expand).toBe(true);
+      expect(component.versionsList[4].expand).toBe(true);
+    });
+
+    it("should stop immediately when the next entry is important", () => {
+      component.versionsList = [makeEntry(3, false), makeEntry(2, true), makeEntry(1, false)];
+
+      component.collapse(0, true);
+
+      // the very next entry (index 1) is important, so nothing is changed
+      expect(component.versionsList[1].expand).toBe(false);
+      expect(component.versionsList[2].expand).toBe(false);
+    });
+  });
+
+  describe("ngOnInit", () => {
+    it("should unhighlight the currently highlighted elements", () => {
+      const wrapper = workflowActionService.getJointGraphWrapper();
+      const highlights = { operators: ["op-1"], groups: [], links: [], commentBoxes: [], ports: [] };
+      vi.spyOn(wrapper, "getCurrentHighlights").mockReturnValue(highlights as any);
+      const unhighlightSpy = vi.spyOn(wrapper, "unhighlightElements").mockImplementation(() => {});
+
+      component.ngOnInit();
+
+      expect(unhighlightSpy).toHaveBeenCalledWith(highlights);
+    });
+
+    it("should not retrieve versions when the route has no workflow id", () => {
+      (component.route.snapshot.params as any).id = undefined;
+      const retrieveSpy = vi.spyOn(workflowVersionService, "retrieveVersionsOfWorkflow");
+      component.versionsList = undefined;
+
+      component.ngOnInit();
+
+      expect(retrieveSpy).not.toHaveBeenCalled();
+      expect(component.versionsList).toBeUndefined();
+    });
+
+    it("should load and map the retrieved versions with expand defaulting to false", () => {
+      const entries: WorkflowVersionEntry[] = [
+        { vId: 10, creationTime: 1000, content: "c10", importance: true },
+        { vId: 9, creationTime: 900, content: "c9", importance: false },
+      ];
+      (component.route.snapshot.params as any).id = 42;
+      const retrieveSpy = vi.spyOn(workflowVersionService, "retrieveVersionsOfWorkflow").mockReturnValue(of(entries));
+
+      component.ngOnInit();
+
+      expect(retrieveSpy).toHaveBeenCalledWith(42);
+      expect(component.versionsList).toEqual([
+        { vId: 10, creationTime: 1000, content: "c10", importance: true, expand: false },
+        { vId: 9, creationTime: 900, content: "c9", importance: false, expand: false },
+      ]);
+    });
+  });
+
+  describe("getVersion", () => {
+    const mockWorkflow = { content: {} } as unknown as Workflow;
+
+    it("should select the row, fetch the version and display it", () => {
+      const retrieveSpy = vi
+        .spyOn(workflowVersionService, "retrieveWorkflowByVersion")
+        .mockReturnValue(of(mockWorkflow));
+      const displaySpy = vi.spyOn(workflowVersionService, "displayParticularVersion").mockImplementation(() => {});
+
+      component.getVersion(7, 3, 2);
+
+      // selected row is recorded immediately (synchronously)
+      expect(component.selectedRowIndex).toBe(2);
+      // wid comes from the workflow metadata (default is 0)
+      expect(retrieveSpy).toHaveBeenCalledWith(0, 7);
+      expect(displaySpy).toHaveBeenCalledWith(mockWorkflow, 7, 3);
+    });
+
+    it("should use the current workflow metadata wid when fetching the version", () => {
+      workflowActionService.setWorkflowMetadata({ ...DEFAULT_WORKFLOW, wid: 99 });
+      const retrieveSpy = vi
+        .spyOn(workflowVersionService, "retrieveWorkflowByVersion")
+        .mockReturnValue(of(mockWorkflow));
+      vi.spyOn(workflowVersionService, "displayParticularVersion").mockImplementation(() => {});
+
+      component.getVersion(4, 1, 0);
+
+      expect(retrieveSpy).toHaveBeenCalledWith(99, 4);
+      expect(component.selectedRowIndex).toBe(0);
+    });
+  });
 });