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


##########
frontend/src/app/dashboard/component/user/list-item/card-item/card-item.component.spec.ts:
##########
@@ -894,4 +895,153 @@ describe("CardItemComponent", () => {
       expect(component.likeCount).toBe(0);
     });
   });
+
+  describe("template rendering", () => {
+    const stop = { stopPropagation: () => {} };
+
+    it("renders the full private-search action set for an owned workflow (and 
no like button)", () => {
+      component.entry = makeWorkflowEntry();
+      component.isPrivateSearch = true;
+      component.currentUid = 1;
+      fixture.detectChanges();
+
+      const de = fixture.debugElement;
+      expect(de.query(By.css(".card-checkbox"))).toBeTruthy();
+      expect(de.query(By.css(".edit-btn"))).toBeTruthy();
+      expect(de.query(By.css('button[title="Detail"]'))).toBeTruthy();
+      expect(de.query(By.css('button[title="Share"]'))).toBeTruthy();
+      expect(de.query(By.css('button[title="Copy"]'))).toBeTruthy();
+      expect(de.query(By.css('button[title="Download"]'))).toBeTruthy();
+      expect(de.query(By.css(".delete-btn"))).toBeTruthy();
+      // the like button is only rendered in non-private mode
+      expect(de.query(By.css(".like-btn"))).toBeNull();
+    });
+
+    it("wires each private-search action click to its handler / output", () => 
{
+      component.entry = makeWorkflowEntry();
+      component.isPrivateSearch = true;
+      component.currentUid = 1;
+      fixture.detectChanges();
+      const de = fixture.debugElement;
+
+      const detailSpy = vi.spyOn(component, 
"openDetailModal").mockImplementation(() => {});
+      const shareSpy = vi.spyOn(component, 
"onClickOpenShareAccess").mockImplementation(async () => {});
+      const downloadSpy = vi.spyOn(component, 
"onClickDownload").mockImplementation(async () => {});
+      let duplicated = false;
+      component.duplicated.subscribe(() => (duplicated = true));
+      let deleted = false;
+      component.deleted.subscribe(() => (deleted = true));
+
+      de.query(By.css('button[title="Detail"]')).triggerEventHandler("click", 
stop);
+      de.query(By.css('button[title="Share"]')).triggerEventHandler("click", 
stop);
+      
de.query(By.css('button[title="Download"]')).triggerEventHandler("click", stop);
+      de.query(By.css('button[title="Copy"]')).triggerEventHandler("click", 
stop);
+      de.query(By.css(".delete-btn")).triggerEventHandler("nzOnConfirm", 
undefined);
+
+      expect(detailSpy).toHaveBeenCalled();
+      expect(shareSpy).toHaveBeenCalled();
+      expect(downloadSpy).toHaveBeenCalled();
+      expect(duplicated).toBe(true);
+      expect(deleted).toBe(true);
+    });
+
+    it("enters name-editing mode from the edit button and swaps the display 
for the input", () => {
+      component.entry = makeWorkflowEntry();
+      component.isPrivateSearch = true;
+      fixture.detectChanges();
+
+      // Trigger via the DOM; onEditName sets editingName synchronously (its 
setTimeout
+      // focus callback never runs in this synchronous test — no fake timers 
needed).
+      
fixture.debugElement.query(By.css(".edit-btn")).triggerEventHandler("click", 
stop);
+      expect(component.editingName).toBe(true);
+
+      fixture.detectChanges();
+      
expect(fixture.debugElement.query(By.css(".resource-name-edit-input"))).toBeTruthy();
+      expect(fixture.debugElement.query(By.css(".resource-name"))).toBeNull();
+
+      // pressing Enter in the edit input confirms the rename (real key event 
so the
+      // Angular keydown.enter binding fires through its event plugin)
+      const confirmSpy = vi.spyOn(component, 
"confirmUpdateCustomName").mockImplementation(() => {});
+      const editInput = 
fixture.debugElement.query(By.css(".resource-name-edit-input"))
+        .nativeElement as HTMLInputElement;
+      editInput.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter" }));
+      expect(confirmSpy).toHaveBeenCalled();
+    });
+
+    it("renders and wires the cover-image controls when the cover is 
editable", () => {
+      component.entry = makeWorkflowEntry();
+      component.isPrivateSearch = true;
+      // hasCustomImage is driven by the private customImage field.
+      (component as unknown as { customImage?: string }).customImage = 
"http://example.com/cover.png";;

Review Comment:
   Switched to driving `hasCustomImage` through the public entry input 
(`coverImageUrl` → `initializeEntry()`), so the test no longer casts to the 
private `customImage` field.
   



##########
frontend/src/app/dashboard/component/user/list-item/card-item/card-item.component.spec.ts:
##########
@@ -894,4 +895,153 @@ describe("CardItemComponent", () => {
       expect(component.likeCount).toBe(0);
     });
   });
+
+  describe("template rendering", () => {
+    const stop = { stopPropagation: () => {} };
+
+    it("renders the full private-search action set for an owned workflow (and 
no like button)", () => {
+      component.entry = makeWorkflowEntry();
+      component.isPrivateSearch = true;
+      component.currentUid = 1;
+      fixture.detectChanges();
+
+      const de = fixture.debugElement;
+      expect(de.query(By.css(".card-checkbox"))).toBeTruthy();
+      expect(de.query(By.css(".edit-btn"))).toBeTruthy();
+      expect(de.query(By.css('button[title="Detail"]'))).toBeTruthy();
+      expect(de.query(By.css('button[title="Share"]'))).toBeTruthy();
+      expect(de.query(By.css('button[title="Copy"]'))).toBeTruthy();
+      expect(de.query(By.css('button[title="Download"]'))).toBeTruthy();
+      expect(de.query(By.css(".delete-btn"))).toBeTruthy();
+      // the like button is only rendered in non-private mode
+      expect(de.query(By.css(".like-btn"))).toBeNull();
+    });
+
+    it("wires each private-search action click to its handler / output", () => 
{
+      component.entry = makeWorkflowEntry();
+      component.isPrivateSearch = true;
+      component.currentUid = 1;
+      fixture.detectChanges();
+      const de = fixture.debugElement;
+
+      const detailSpy = vi.spyOn(component, 
"openDetailModal").mockImplementation(() => {});
+      const shareSpy = vi.spyOn(component, 
"onClickOpenShareAccess").mockImplementation(async () => {});
+      const downloadSpy = vi.spyOn(component, 
"onClickDownload").mockImplementation(async () => {});
+      let duplicated = false;
+      component.duplicated.subscribe(() => (duplicated = true));
+      let deleted = false;
+      component.deleted.subscribe(() => (deleted = true));
+
+      de.query(By.css('button[title="Detail"]')).triggerEventHandler("click", 
stop);
+      de.query(By.css('button[title="Share"]')).triggerEventHandler("click", 
stop);
+      
de.query(By.css('button[title="Download"]')).triggerEventHandler("click", stop);
+      de.query(By.css('button[title="Copy"]')).triggerEventHandler("click", 
stop);
+      de.query(By.css(".delete-btn")).triggerEventHandler("nzOnConfirm", 
undefined);

Review Comment:
   Added a `fire()` helper that queries, asserts the element is present, then 
dispatches the event — so a broken selector fails with a clear message instead 
of a null dereference.
   



##########
frontend/src/app/dashboard/component/user/list-item/card-item/card-item.component.spec.ts:
##########
@@ -894,4 +895,153 @@ describe("CardItemComponent", () => {
       expect(component.likeCount).toBe(0);
     });
   });
+
+  describe("template rendering", () => {
+    const stop = { stopPropagation: () => {} };
+
+    it("renders the full private-search action set for an owned workflow (and 
no like button)", () => {
+      component.entry = makeWorkflowEntry();
+      component.isPrivateSearch = true;
+      component.currentUid = 1;
+      fixture.detectChanges();
+
+      const de = fixture.debugElement;
+      expect(de.query(By.css(".card-checkbox"))).toBeTruthy();
+      expect(de.query(By.css(".edit-btn"))).toBeTruthy();
+      expect(de.query(By.css('button[title="Detail"]'))).toBeTruthy();
+      expect(de.query(By.css('button[title="Share"]'))).toBeTruthy();
+      expect(de.query(By.css('button[title="Copy"]'))).toBeTruthy();
+      expect(de.query(By.css('button[title="Download"]'))).toBeTruthy();
+      expect(de.query(By.css(".delete-btn"))).toBeTruthy();
+      // the like button is only rendered in non-private mode
+      expect(de.query(By.css(".like-btn"))).toBeNull();
+    });
+
+    it("wires each private-search action click to its handler / output", () => 
{
+      component.entry = makeWorkflowEntry();
+      component.isPrivateSearch = true;
+      component.currentUid = 1;
+      fixture.detectChanges();
+      const de = fixture.debugElement;
+
+      const detailSpy = vi.spyOn(component, 
"openDetailModal").mockImplementation(() => {});
+      const shareSpy = vi.spyOn(component, 
"onClickOpenShareAccess").mockImplementation(async () => {});
+      const downloadSpy = vi.spyOn(component, 
"onClickDownload").mockImplementation(async () => {});
+      let duplicated = false;
+      component.duplicated.subscribe(() => (duplicated = true));
+      let deleted = false;
+      component.deleted.subscribe(() => (deleted = true));
+
+      de.query(By.css('button[title="Detail"]')).triggerEventHandler("click", 
stop);
+      de.query(By.css('button[title="Share"]')).triggerEventHandler("click", 
stop);
+      
de.query(By.css('button[title="Download"]')).triggerEventHandler("click", stop);
+      de.query(By.css('button[title="Copy"]')).triggerEventHandler("click", 
stop);
+      de.query(By.css(".delete-btn")).triggerEventHandler("nzOnConfirm", 
undefined);
+
+      expect(detailSpy).toHaveBeenCalled();
+      expect(shareSpy).toHaveBeenCalled();
+      expect(downloadSpy).toHaveBeenCalled();
+      expect(duplicated).toBe(true);
+      expect(deleted).toBe(true);
+    });
+
+    it("enters name-editing mode from the edit button and swaps the display 
for the input", () => {
+      component.entry = makeWorkflowEntry();
+      component.isPrivateSearch = true;
+      fixture.detectChanges();
+
+      // Trigger via the DOM; onEditName sets editingName synchronously (its 
setTimeout
+      // focus callback never runs in this synchronous test — no fake timers 
needed).
+      
fixture.debugElement.query(By.css(".edit-btn")).triggerEventHandler("click", 
stop);

Review Comment:
   Intentionally not using fake timers here: issue #7330 calls this out 
explicitly — layering `vi.useFakeTimers()` over zone.js's patched timers is 
Node-version-dependent and has caused CI-only failures in this repo. The test 
body is synchronous, so `onEditName`'s `setTimeout` focus callback never runs; 
the test asserts `editingName` / the rendered input rather than the focus.
   



##########
frontend/src/app/dashboard/component/user/list-item/card-item/card-item.component.spec.ts:
##########
@@ -894,4 +895,153 @@ describe("CardItemComponent", () => {
       expect(component.likeCount).toBe(0);
     });
   });
+
+  describe("template rendering", () => {
+    const stop = { stopPropagation: () => {} };

Review Comment:
   Clicks now dispatch a real `MouseEvent`, so handlers calling 
`stopPropagation()` / `preventDefault()` work.
   



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