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-7470-dafccec7990fb3aec6b2b07b919051eccc115176 in repository https://gitbox.apache.org/repos/asf/texera.git
commit ab4d25eb16fdd4b1b4ac74a890ea3eaba62b5e0a Author: Meng Wang <[email protected]> AuthorDate: Sun Aug 9 16:09:34 2026 -0700 test(frontend): cover HuggingFaceImageUploadComponent template preview and error states (#7470) ### What changes were proposed in this PR? Extends `HuggingFaceImageUploadComponent`'s spec to render the template. The class file is already at 100%, but the existing tests only drive the handlers directly, so the preview panel never rendered and `hugging-face-image-upload.component.html` sat at ~32%. 7 added tests render the component and assert on the DOM: - No preview panel while no image is selected. - The preview `<img>` is bound to the stored data URL (`src`, `alt`). - The panel's label falls back to `"Uploaded image"` when no file name is known, and shows the selected file name once one is. - The **Clear** button clears the control and removes the panel. - The error block renders the current `errorMessage`. - A `change` event with no file selected leaves the control untouched — this also covers the file input's `(change)` binding while staying fully synchronous (the guard returns before any `FileReader`/canvas work). This lifts the template from **~32% to 100% statements**. Branches land at 50%, which is the maximum reachable — see below. **The `"Selected image"` fallback is unreachable.** The issue asks for a test where `displayFileName` is empty so `{{ displayFileName || "Selected image" }}` renders the fallback, but that state cannot occur: - the panel only renders when `previewSrc` is truthy, which requires `hasImage`; - `displayFileName` returns `fileName` when set, otherwise `"Uploaded image"` when `hasImage` — so with `hasImage` true it is never empty. So whenever the fallback could be shown, the left-hand side is already truthy. I did not force it with a fabricated getter override, since that would assert a state the component cannot reach. If desired, the template could simply become `{{ displayFileName }}` in a follow-up — left out here because this change is test-only. **Determinism:** no fake timers and no async image pipeline in the added tests (the no-file `change` path returns synchronously); no layout/geometry assertions. No production code was changed. ### Any related issues, documentation, discussions? Closes #7467 ### How was this PR tested? Extended unit tests, run locally in `frontend/`: ``` ng test --watch=false --include src/app/workspace/component/hugging-face-image-upload/hugging-face-image-upload.component.spec.ts # Test Files 1 passed (1) | Tests 42 passed (42) — 3 consecutive runs, 0 flakes # hugging-face-image-upload.component.html: ~32% -> 100% statements prettier --write <spec> # formatted eslint <spec> # clean ``` The failure path was verified by deliberately breaking a new assertion and confirming the suite exits non-zero. ### Was this PR authored or co-authored using generative AI tooling? Generated-by: Claude Code (Opus 4.8 [1M context]) --- .../hugging-face-image-upload.component.spec.ts | 76 ++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/frontend/src/app/workspace/component/hugging-face-image-upload/hugging-face-image-upload.component.spec.ts b/frontend/src/app/workspace/component/hugging-face-image-upload/hugging-face-image-upload.component.spec.ts index e22a4f5715..62bac27019 100644 --- a/frontend/src/app/workspace/component/hugging-face-image-upload/hugging-face-image-upload.component.spec.ts +++ b/frontend/src/app/workspace/component/hugging-face-image-upload/hugging-face-image-upload.component.spec.ts @@ -18,6 +18,7 @@ */ import { ComponentFixture, TestBed } from "@angular/core/testing"; +import { By } from "@angular/platform-browser"; import { FormControl } from "@angular/forms"; import { HuggingFaceImageUploadComponent } from "./hugging-face-image-upload.component"; import { commonTestProviders } from "../../../common/testing/test-utils"; @@ -603,4 +604,79 @@ describe("HuggingFaceImageUploadComponent", () => { } }); }); + + // ── Rendered template ── + + describe("template rendering", () => { + const DATA_URL = "data:image/jpeg;base64,AAA"; + + const preview = () => fixture.debugElement.query(By.css(".hf-image-preview")); + + /** Put the component in the "image selected" state and render it. */ + function renderWithImage(fileName = ""): void { + component.fileName = fileName; + component.formControl.setValue(DATA_URL); + fixture.detectChanges(); + } + + it("renders no preview panel while no image is selected", () => { + expect(preview()).toBeNull(); + }); + + it("renders the preview image bound to the stored data URL", () => { + renderWithImage(); + + expect(preview()).toBeTruthy(); + const img = fixture.debugElement.query(By.css(".hf-image-preview img")); + expect(img.nativeElement.getAttribute("src")).toBe(DATA_URL); + expect(img.nativeElement.getAttribute("alt")).toBe("Uploaded Hugging Face task input"); + }); + + it("labels the preview with the default text when no file name is known", () => { + renderWithImage(); + + expect(fixture.debugElement.query(By.css(".hf-image-meta span")).nativeElement.textContent.trim()).toBe( + "Uploaded image" + ); + }); + + it("labels the preview with the selected file name once one is known", () => { + renderWithImage("cat.png"); + + expect(fixture.debugElement.query(By.css(".hf-image-meta span")).nativeElement.textContent.trim()).toBe( + "cat.png" + ); + }); + + it("the Clear button clears the image and removes the preview panel", () => { + renderWithImage("cat.png"); + + fixture.debugElement.query(By.css(".hf-image-meta button")).triggerEventHandler("click", null); + fixture.detectChanges(); + + expect(component.formControl.value).toBe(""); + expect(component.fileName).toBe(""); + expect(preview()).toBeNull(); + }); + + it("renders the error message when one is set", () => { + component.errorMessage = "Choose an image file."; + fixture.detectChanges(); + + const error = fixture.debugElement.query(By.css(".hf-image-error")); + expect(error).toBeTruthy(); + expect(error.nativeElement.textContent.trim()).toBe("Choose an image file."); + }); + + it("a change event with no file selected leaves the control untouched", () => { + const input = fixture.debugElement.query(By.css("input[type='file']")); + + input.nativeElement.dispatchEvent(new Event("change")); + fixture.detectChanges(); + + expect(component.formControl.value).toBe(""); + expect(component.errorMessage).toBe(""); + expect(preview()).toBeNull(); + }); + }); });
