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


##########
frontend/src/app/dashboard/component/user/user-workflow/ngbd-modal-workflow-executions/workflow-execution-history.component.spec.ts:
##########
@@ -729,4 +733,225 @@ describe("WorkflowExecutionHistoryComponent", () => {
       expect(fixture.nativeElement.querySelectorAll(".ant-card-actions 
i")).toHaveLength(2);
     });
   });
+
+  // ──────────────────────────────────────────────────────────────────────────
+  // Interactions driven through the rendered markup rather than the instance,
+  // so the template's own event bindings are the code under test.
+  // ──────────────────────────────────────────────────────────────────────────
+  describe("template-driven interactions", () => {
+    function headerCells(): DebugElement[] {
+      return fixture.debugElement.queryAll(By.css("thead th"));
+    }
+
+    function bodyRows(): DebugElement[] {
+      return fixture.debugElement.queryAll(By.css("tbody tr"));
+    }
+
+    /** The card's two group actions render in [nzActions] order: bookmark, 
then delete. */
+    function groupActions(): { bookmark: DebugElement; delete: DebugElement } {
+      const icons = fixture.debugElement.queryAll(By.css(".ant-card-actions 
i"));
+      return { bookmark: icons[0], delete: icons[1] };
+    }
+
+    function sortButtonFor(column: string): DebugElement {
+      const header = headerCells().find(th => (th.nativeElement as 
HTMLElement).textContent?.includes(column));
+      return header!.query(By.css("button"));
+    }
+
+    /** Row buttons in template order: rename (.rename-icon), runtime 
statistics, delete. */
+    function rowButtons(row: DebugElement): { statistics: DebugElement; 
delete: DebugElement } {
+      const buttons = row.queryAll(By.css("button:not(.rename-icon)"));
+      return { statistics: buttons[0], delete: buttons[1] };
+    }
+
+    it("searches from the rendered input when Enter is pressed in it", async 
() => {
+      await setup();
+      const searchSpy = vi.spyOn(component.fuse, 
"search").mockReturnValue(fuseResults(entries[0]));
+      component.executionSearchValue = "status:running";
+      fixture.detectChanges();
+
+      
fixture.debugElement.query(By.css("input[nz-input]")).triggerEventHandler("keyup.enter",
 {});
+
+      expect(searchSpy).toHaveBeenCalledWith({ $and: [{ $path: ["status"], 
$val: "1" }] });
+      expect(component.workflowExecutionsDisplayedList).toEqual([entries[0]]);
+    });
+
+    it("feeds the autocomplete as the rendered input changes", async () => {
+      await setup();
+
+      
fixture.debugElement.query(By.css("input[nz-input]")).triggerEventHandler("ngModelChange",
 "status:run");
+
+      expect(component.filteredExecutionInfo).toEqual(["status:running"]);
+    });
+
+    it("renders the search-criteria help once the instructions popover is 
opened", async () => {
+      await setup();
+      const popover = 
fixture.debugElement.query(By.directive(NzPopoverDirective)).injector.get(NzPopoverDirective);
+
+      popover.show();
+      fixture.detectChanges();
+      // the tooltip base positions its overlay in a microtask, so flush that 
before reading it
+      await Promise.resolve();
+      fixture.detectChanges();
+
+      // the popover content lives in the cdk overlay, outside the fixture's 
own element
+      const help = 
document.querySelector(".cdk-overlay-container")?.textContent ?? "";
+      expect(help).toContain("We support the following search criteria");
+      expect(help).toContain("executionName");
+      expect(help).toContain("user:John");
+      
expect(help).toContain("status:initializing/running/paused/completed/failed/killed");
+      expect(help).toContain("using double quotes to enclose the name is");
+      expect(help).toContain('Example: "Untitled Execution" user:John');
+
+      popover.hide();
+      fixture.detectChanges();
+    });
+
+    it("bookmarks the whole selection from the card's group action", async () 
=> {
+      await setup();
+      component.onItemChecked(entries[0], true);
+      component.onItemChecked(entries[2], true);
+      fixture.detectChanges();
+
+      groupActions().bookmark.triggerEventHandler("click", new 
MouseEvent("click"));
+
+      expect(executionsService.groupSetIsBookmarked).toHaveBeenCalledWith(1, 
[1, 3], false);
+      expect(entries[0].bookmarked).toBe(true);
+      expect(entries[2].bookmarked).toBe(true);
+    });
+
+    it("deletes the whole selection when the group popconfirm is confirmed", 
async () => {
+      await setup();
+      component.onItemChecked(entries[0], true);
+      fixture.detectChanges();
+
+      groupActions().delete.triggerEventHandler("nzOnConfirm", undefined);
+
+      
expect(executionsService.groupDeleteWorkflowExecutions).toHaveBeenCalledWith(1, 
[1]);
+      expect(component.allExecutionEntries.map(e => e.eId)).toEqual([2, 3]);
+      expect(component.setOfEid.size).toBe(0);
+    });
+
+    it("re-slices the table when the paginator reports a new page index", 
async () => {
+      const many = Array.from({ length: 15 }, (_, i) => makeEntry({ eId: i + 
1, name: `run ${i + 1}` }));
+      await setup({ entries: many });
+
+      const table = fixture.debugElement.query(By.css("nz-table"));
+      table.triggerEventHandler("nzPageIndexChange", 2);
+
+      expect(component.currentPageIndex).toBe(2);
+      expect(component.workflowExecutionsDisplayedList!.map(e => 
e.eId)).toEqual([11, 12, 13, 14, 15]);
+
+      table.triggerEventHandler("nzPageSizeChange", 5);
+
+      expect(component.pageSize).toBe(5);
+      expect(component.workflowExecutionsDisplayedList!.map(e => 
e.eId)).toEqual([6, 7, 8, 9, 10]);
+    });
+
+    it("selects and clears every row from the header checkbox", async () => {
+      await setup();
+      headerCells()[0].triggerEventHandler("nzCheckedChange", true);
+
+      expect(component.setOfEid).toEqual(new Set([1, 2, 3]));
+      expect(component.checked).toBe(true);
+
+      headerCells()[0].triggerEventHandler("nzCheckedChange", false);
+
+      expect(component.setOfEid.size).toBe(0);
+      expect(component.checked).toBe(false);
+    });
+
+    it("sorts descending from a header whose arrow points down", async () => {
+      await setup();
+      // showORhide[2] is false for "Name (ID)", so its header renders the 
descending button.
+      sortButtonFor("Name (ID)").triggerEventHandler("click", new 
MouseEvent("click"));
+
+      expect(component.workflowExecutionsDisplayedList!.map(e => 
e.name)).toEqual([
+        "Untitled Execution",
+        "twitter analysis",
+        "reddit crawl",
+      ]);
+      expect(component.showORhide[2]).toBe(true);
+    });
+
+    it("sorts ascending from a header whose arrow points up", async () => {
+      await setup();
+      // showORhide[4] starts true, so "Execution Start Time" renders the 
ascending button.
+      sortButtonFor("Execution Start Time").triggerEventHandler("click", new 
MouseEvent("click"));
+
+      expect(component.workflowExecutionsDisplayedList!.map(e => 
e.eId)).toEqual([1, 2, 3]);
+      expect(component.showORhide[4]).toBe(false);
+    });

Review Comment:
   Good catch — the default fixtures are already ascending by startingTime, so 
that assertion held with or without the click. The rows are now seeded against 
eId order and the test asserts the order both before and after the click. 
Verified it goes red when the click is removed, which the previous version did 
not.



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