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-6760-1b24f3d26da23ccbcfbab07d7c84707502f15b55
in repository https://gitbox.apache.org/repos/asf/texera.git

commit b2ee4f6d69ff60cbe8a3c69b7e37613809a80178
Author: Meng Wang <[email protected]>
AuthorDate: Tue Jul 21 22:43:23 2026 -0700

    test(frontend): cover ListItemComponent edit helpers and 
FilesUploaderComponent conflict prompts (#6760)
    
    ### What changes were proposed in this PR?
    
    Extends two dashboard component specs to cover their remaining untested
    edit/interaction methods (Vitest; no production code changed).
    
    **`ListItemComponent`** (+5 tests) — `setEditingState` (toggles the name
    /
    description edit flags), `renderMarkdownPreview` (strips markdown syntax
    and
    collapses whitespace), and `updateProperty` (missing-id guard, success
    persistence + exit-edit-mode, and error revert + notify).
    
    > Note: the other ListItem methods the issue lists (`onEditName` /
    > `onEditDescription` / `toggleLike` / `onCheckboxChange` /
    `openDetailModal` /
    > `initializeEntry` / `confirmUpdate*`) are already covered on `main`
    (added in
    > #6557), so this PR only fills the remaining gaps.
    
    **`FilesUploaderComponent`** (+4 tests) — `markForceRestart` (flags the
    item),
    `getOwnerAndName` (returns the owner/name inputs), and `askResumeOrSkip`
    /
    `askUploadOrSkip` (resolve with the clicked conflict-modal footer
    action). The
    modal is driven through the spec's existing capturing double.
    
    ### Any related issues, documentation, discussions?
    
    Closes #6749
    
    ### How was this PR tested?
    
    Extended unit tests, run locally in `frontend/` (all green; each spec's
    failure
    path was verified by breaking an assertion to confirm it goes red):
    
    ```
    ng test --watch=false --include 
src/app/dashboard/component/user/list-item/list-item.component.spec.ts        # 
25 passed
    ng test --watch=false --include 
src/app/dashboard/component/user/files-uploader/files-uploader.component.spec.ts
 # 12 passed
    prettier --write <specs>   # clean
    eslint  <specs>            # clean
    ```
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Opus 4.8 [1M context])
---
 .../files-uploader.component.spec.ts               | 39 ++++++++++++
 .../user/list-item/list-item.component.spec.ts     | 70 ++++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git 
a/frontend/src/app/dashboard/component/user/files-uploader/files-uploader.component.spec.ts
 
b/frontend/src/app/dashboard/component/user/files-uploader/files-uploader.component.spec.ts
index 43398d7efa..88f04e2efc 100644
--- 
a/frontend/src/app/dashboard/component/user/files-uploader/files-uploader.component.spec.ts
+++ 
b/frontend/src/app/dashboard/component/user/files-uploader/files-uploader.component.spec.ts
@@ -219,4 +219,43 @@ describe("FilesUploaderComponent", () => {
     expect(component.fileUploadBannerType).toBe("warning");
     expect(component.fileUploadBannerMessage).toBe("heads up");
   });
+
+  describe("force-restart, owner/name, and conflict prompts", () => {
+    type Item = { name: string; file: { size: number }; restart?: boolean };
+    const asComp = () =>
+      component as unknown as {
+        markForceRestart: (i: Item) => void;
+        getOwnerAndName: () => { ownerEmail: string; datasetName: string };
+        askResumeOrSkip: (i: Item, showForAll: boolean) => Promise<string>;
+        askUploadOrSkip: (i: Item, showForAll: boolean) => Promise<string>;
+      };
+    const lastFooter = () =>
+      (modals[modals.length - 1] as unknown as { nzFooter: Array<{ label: 
string; onClick: () => void }> }).nzFooter;
+
+    it("markForceRestart flags the item for a forced restart", () => {
+      const item: Item = { name: "f.csv", file: { size: 1 }, restart: false };
+      asComp().markForceRestart(item);
+      expect(item.restart).toBe(true);
+    });
+
+    it("getOwnerAndName returns the owner email and dataset name inputs", () 
=> {
+      expect(asComp().getOwnerAndName()).toEqual({ ownerEmail: 
"[email protected]", datasetName: "dataset" });
+    });
+
+    it("askResumeOrSkip resolves with the clicked footer action", async () => {
+      const promise = asComp().askResumeOrSkip({ name: "owner/data/f.csv", 
file: { size: 100 } }, true);
+      lastFooter()
+        .find(b => b.label === "Resume")!
+        .onClick();
+      await expect(promise).resolves.toBe("resume");
+    });
+
+    it("askUploadOrSkip resolves with the clicked footer action", async () => {
+      const promise = asComp().askUploadOrSkip({ name: "owner/data/f.csv", 
file: { size: 100 } }, false);
+      lastFooter()
+        .find(b => b.label === "Skip")!
+        .onClick();
+      await expect(promise).resolves.toBe("skip");
+    });
+  });
 });
diff --git 
a/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
 
b/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
index eca823a4ee..3e7bc25c0c 100644
--- 
a/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
+++ 
b/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
@@ -350,4 +350,74 @@ describe("ListItemComponent", () => {
       expect(component.viewCount).toBe(5); // 4 + 1
     });
   });
+
+  describe("editing state, markdown preview, and updateProperty", () => {
+    const asComp = () =>
+      component as unknown as {
+        setEditingState: (p: "name" | "description", s: boolean) => void;
+        renderMarkdownPreview: (t: string | undefined) => void;
+        updateProperty: (
+          m: (id: number, v: string) => unknown,
+          p: "name" | "description",
+          v: string,
+          o: string | undefined
+        ) => void;
+      };
+
+    it("setEditingState toggles the name / description edit flags", () => {
+      asComp().setEditingState("name", true);
+      expect(component.editingName).toBe(true);
+      asComp().setEditingState("description", true);
+      expect(component.editingDescription).toBe(true);
+      asComp().setEditingState("name", false);
+      expect(component.editingName).toBe(false);
+    });
+
+    it("renderMarkdownPreview strips markdown syntax and collapses 
whitespace", () => {
+      asComp().renderMarkdownPreview("# **Hello**  [link](http://x)");
+      expect(component.renderedDescription).toBe("Hello link");
+      asComp().renderMarkdownPreview("   ");
+      expect(component.renderedDescription).toBe("");
+      asComp().renderMarkdownPreview(undefined);
+      expect(component.renderedDescription).toBe("");
+    });
+
+    it("updateProperty reports a missing id and skips the update", () => {
+      const errorSpy = vi.spyOn(TestBed.inject(NotificationService), "error");
+      component.entry = { name: "x", type: "workflow" } as unknown as 
DashboardEntry;
+      const updateMethod = vi.fn();
+
+      asComp().updateProperty(updateMethod, "name", "new", "old");
+
+      expect(errorSpy).toHaveBeenCalledWith("Id is missing");
+      expect(updateMethod).not.toHaveBeenCalled();
+    });
+
+    it("updateProperty persists the new value and exits edit mode on success", 
() => {
+      component.entry = { id: 1, name: "old", type: "workflow" } as unknown as 
DashboardEntry;
+      component.editingName = true;
+      const updateMethod = vi.fn(() => of({}));
+
+      asComp().updateProperty(updateMethod, "name", "new-name", "old");
+
+      expect(updateMethod).toHaveBeenCalledWith(1, "new-name");
+      expect(component.entry.name).toBe("new-name");
+      expect(component.editingName).toBe(false);
+    });
+
+    it("updateProperty reverts to the original value and exits edit mode on 
error", () => {
+      const errorSpy = vi.spyOn(TestBed.inject(NotificationService), "error");
+      // The name field is two-way bound, so entry.name already holds the 
edited
+      // value by the time updateProperty runs; the error handler must roll it 
back.
+      component.entry = { id: 1, name: "new-name", type: "workflow" } as 
unknown as DashboardEntry;
+      component.editingName = true;
+      const updateMethod = vi.fn(() => throwError(() => new Error("boom")));
+
+      asComp().updateProperty(updateMethod, "name", "new-name", "old");
+
+      expect(component.entry.name).toBe("old");
+      expect(errorSpy).toHaveBeenCalled();
+      expect(component.editingName).toBe(false);
+    });
+  });
 });

Reply via email to