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-6782-1988b1755e0d6d9490fa17b12888e6d6be042759 in repository https://gitbox.apache.org/repos/asf/texera.git
commit e4c294a10a7e67f09350522f14eb7ccc7a9be5cd Author: Xinyuan Lin <[email protected]> AuthorDate: Wed Jul 22 17:07:37 2026 -0700 test(frontend): extend NzModalCommentBoxComponent unit test coverage (#6782) ### What changes were proposed in this PR? Extends `nz-modal-comment-box.component.spec.ts` with 7 tests (8 -> 15), covering `toggleEditInput` open/close/missing-DOM-target branches, the `editComment` no-user guard and DOM-hide tail, and the `window:keydown` Ctrl+Enter host-binding. Coverage ~67% -> 100% lines. No existing tests modified. ### Any related issues, documentation, discussions? Closes #6776. ### How was this PR tested? `ng test --include='**/nz-modal-comment-box.component.spec.ts'` -> 15/15 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]) --- .../nz-modal-comment-box.component.spec.ts | 127 ++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/workspace/component/workflow-editor/comment-box-modal/nz-modal-comment-box.component.spec.ts b/frontend/src/app/workspace/component/workflow-editor/comment-box-modal/nz-modal-comment-box.component.spec.ts index 7506be96a4..61d41276a2 100644 --- a/frontend/src/app/workspace/component/workflow-editor/comment-box-modal/nz-modal-comment-box.component.spec.ts +++ b/frontend/src/app/workspace/component/workflow-editor/comment-box-modal/nz-modal-comment-box.component.spec.ts @@ -39,6 +39,32 @@ describe("NzModalCommentBoxComponent", () => { let addComment: ReturnType<typeof vi.fn>; let deleteComment: ReturnType<typeof vi.fn>; let editComment: ReturnType<typeof vi.fn>; + let lastFixture: ComponentFixture<NzModalCommentBoxComponent> | undefined; + let createdEls: HTMLElement[] = []; + + // toggleEditInput / editComment locate their DOM targets by id + // ("txarea"|"comment"|"editbtn" + creatorName + creationTime). Build real + // elements so those document.getElementById lookups resolve. + function makeEl(id: string, opts: { hidden?: boolean; text?: string } = {}): HTMLElement { + const el = document.createElement("div"); + el.id = id; + if (opts.hidden) { + el.setAttribute("hidden", "hidden"); + } + if (opts.text !== undefined) { + el.textContent = opts.text; + } + document.body.appendChild(el); + createdEls.push(el); + return el; + } + + afterEach(() => { + lastFixture?.destroy(); + lastFixture = undefined; + createdEls.forEach(el => el.remove()); + createdEls = []; + }); async function createFixture( opts: { user?: User; comments?: unknown[] } = {} @@ -65,7 +91,8 @@ describe("NzModalCommentBoxComponent", () => { ], }).compileComponents(); - return TestBed.createComponent(NzModalCommentBoxComponent); + lastFixture = TestBed.createComponent(NzModalCommentBoxComponent); + return lastFixture; } it("should create and render a comment from the box", async () => { @@ -158,4 +185,102 @@ describe("NzModalCommentBoxComponent", () => { component.onKeyDown(new KeyboardEvent("keydown", { key: "a", ctrlKey: true })); expect(submitSpy).toHaveBeenCalledTimes(1); }); + + describe("edit flows", () => { + it("toggleEditInput is a no-op when its DOM targets are missing", async () => { + const fixture = await createFixture({ user: makeUser() }); + const component = fixture.componentInstance; + component.editValue = "preset"; + + // No txarea/comment/editbtn elements exist for this name+time. + component.toggleEditInput("Ghost", CREATION_TIME); + + expect(component.editValue).toBe("preset"); // early return leaves state untouched + }); + + it("toggleEditInput opens the editor, hides the comment, and loads its text", async () => { + const fixture = await createFixture({ user: makeUser() }); + const component = fixture.componentInstance; + const name = "Bob"; + const txarea = makeEl("txarea" + name + CREATION_TIME, { hidden: true }); + const comment = makeEl("comment" + name + CREATION_TIME, { text: "original text" }); + const btn = makeEl("editbtn" + name + CREATION_TIME, { hidden: true }); + + component.toggleEditInput(name, CREATION_TIME); + + expect(txarea.hasAttribute("hidden")).toBe(false); + expect(btn.hasAttribute("hidden")).toBe(false); + expect(comment.hasAttribute("hidden")).toBe(true); + expect(component.editValue).toBe("original text"); + }); + + it("toggleEditInput closes the editor and clears editValue on the second toggle", async () => { + const fixture = await createFixture({ user: makeUser() }); + const component = fixture.componentInstance; + const name = "Bob"; + const txarea = makeEl("txarea" + name + CREATION_TIME, { hidden: true }); + const comment = makeEl("comment" + name + CREATION_TIME, { text: "original text" }); + const btn = makeEl("editbtn" + name + CREATION_TIME, { hidden: true }); + + component.toggleEditInput(name, CREATION_TIME); // open + component.toggleEditInput(name, CREATION_TIME); // close + + expect(txarea.hasAttribute("hidden")).toBe(true); + expect(btn.hasAttribute("hidden")).toBe(true); + expect(comment.hasAttribute("hidden")).toBe(false); + expect(component.editValue).toBe(""); + }); + + it("editComment is a no-op without a current user and preserves editValue", async () => { + const fixture = await createFixture({ user: undefined }); + const component = fixture.componentInstance; + component.editValue = "attempted edit"; + + component.editComment(1, "Alice", CREATION_TIME); + + expect(editComment).not.toHaveBeenCalled(); + expect(component.editValue).toBe("attempted edit"); // reset happens only past the guard + }); + + it("editComment saves the new content and then hides the edit textarea and button", async () => { + const fixture = await createFixture({ user: makeUser() }); + const component = fixture.componentInstance; + const name = "Carol"; + const txarea = makeEl("txarea" + name + CREATION_TIME); // visible + const btn = makeEl("editbtn" + name + CREATION_TIME); // visible + component.editValue = "edited body"; + + component.editComment(2, name, CREATION_TIME); + + expect(editComment).toHaveBeenCalledWith(2, CREATION_TIME, BOX_ID, "edited body"); + expect(component.editValue).toBe(""); + expect(txarea.hasAttribute("hidden")).toBe(true); + expect(btn.hasAttribute("hidden")).toBe(true); + }); + + it("editComment still saves when the edit DOM targets are absent (guarded tail)", async () => { + const fixture = await createFixture({ user: makeUser() }); + const component = fixture.componentInstance; + component.editValue = "no-dom edit"; + + // No txarea/editbtn elements: the service call happens, the DOM tail short-circuits. + component.editComment(3, "Nobody", CREATION_TIME); + + expect(editComment).toHaveBeenCalledWith(3, CREATION_TIME, BOX_ID, "no-dom edit"); + expect(component.editValue).toBe(""); + }); + }); + + it("the window:keydown host binding submits the comment on Ctrl+Enter", async () => { + const fixture = await createFixture({ user: makeUser() }); + fixture.detectChanges(); // register the @HostListener("window:keydown") binding + fixture.componentInstance.inputValue = "via host listener"; + + const event = new KeyboardEvent("keydown", { key: "Enter", ctrlKey: true, cancelable: true }); + window.dispatchEvent(event); + + expect(addComment).toHaveBeenCalledTimes(1); + expect(addComment.mock.calls[0][0]).toMatchObject({ content: "via host listener" }); + expect(event.defaultPrevented).toBe(true); + }); });
