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-7535-61f22afc1f9fd7c4833fbf54e621dcbef9068eac
in repository https://gitbox.apache.org/repos/asf/texera.git

commit dcecfa69fd9a94319f931221e7f99420e9d5970b
Author: Xinyuan Lin <[email protected]>
AuthorDate: Mon Aug 10 23:41:08 2026 -0700

    test(frontend): render the hub workflow detail with its real children 
(#7535)
    
    ### What changes were proposed in this PR?
    
    `hub-workflow-detail.component.html` reported 0 of 46 lines while its
    own `.ts` sat at 98% — the
    attribution loss from #7458, not a testing gap. The spec stubs its three
    children out through
    `TestBed.overrideComponent`, and any override re-JITs the component from
    its decorator metadata; the
    re-compiled template has no source map back to the `.html`, so the
    bindings execute uncounted.
    
    Adds a `describe` block that renders the component with its real
    children. That restores
    attribution:
    
    | | Before | After |
    |---|---|---|
    | lines | 0/46 (0.0%) | **45/46 (97.8%)** |
    | branches | — | 3/3 |
    
    Three tests: the real editor and mini-map resolving rather than the stub
    selectors, and the
    `*ngIf="isHub"` back button appearing and not appearing. It keeps its
    own `TestBed` so the 32 tests
    above retain their mocked `WorkflowActionService` and the ten assertions
    they make on it — the real
    service is needed here only because the real editor injects
    `DynamicSchemaService`, which reads the
    graph's operator streams.
    
    ### Verification
    
    Both `*ngIf` mutations were applied to the template and reverted
    (production diff empty):
    
    | Mutation | Result |
    |---|---|
    | back button always rendered (`*ngIf="true"`) | red |
    | back button never rendered (`*ngIf="false"`) | red |
    
    Two assertions in the first test are honestly **guards, not behaviour
    pins**: renaming the child
    elements only breaks the template build rather than producing a clean
    behavioural failure, so they
    are there to stop the override creeping back in, and the coverage
    measurement above is their real
    evidence. Saying so rather than listing them as killed mutations.
    
    One assertion was dropped during review of my own work: the clone
    button's
    `[disabled]="!isLogin || !isHub || !isActivatedUser"` does not reflect
    to the DOM `disabled`
    property under this fixture (it stays `false` with `isHub === false`),
    so asserting on it would have
    been either vacuous or wrong. The back button discriminates cleanly and
    is what the tests use.
    
    No production file is touched.
    
    ### Any related issues, documentation, discussions?
    
    Closes #7534
    
    ### How was this PR tested?
    
    ```
    npx ng test --watch=false 
--include="**/hub-workflow-detail.component.spec.ts"
    ```
    
    ```
     Test Files  1 passed (1)
          Tests  35 passed (35)
    ```
    
    3 new on top of the existing 32. `yarn format:ci` passes.
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Opus 5)
---
 .../detail/hub-workflow-detail.component.spec.ts   | 101 +++++++++++++++++++++
 1 file changed, 101 insertions(+)

diff --git 
a/frontend/src/app/hub/component/workflow/detail/hub-workflow-detail.component.spec.ts
 
b/frontend/src/app/hub/component/workflow/detail/hub-workflow-detail.component.spec.ts
index cefc1e0194..2e45eaa8e0 100644
--- 
a/frontend/src/app/hub/component/workflow/detail/hub-workflow-detail.component.spec.ts
+++ 
b/frontend/src/app/hub/component/workflow/detail/hub-workflow-detail.component.spec.ts
@@ -40,6 +40,13 @@ import { MarkdownDescriptionComponent } from 
"../../../../dashboard/component/us
 import { WorkflowEditorComponent } from 
"../../../../workspace/component/workflow-editor/workflow-editor.component";
 import { MiniMapComponent } from 
"../../../../workspace/component/workflow-editor/mini-map/mini-map.component";
 import { commonTestProviders } from "../../../../common/testing/test-utils";
+import { DragDropModule } from "@angular/cdk/drag-drop";
+import { MarkdownService } from "ngx-markdown";
+import {
+  workflowEditorTestImports,
+  workflowEditorTestProviders,
+} from 
"../../../../workspace/component/workflow-editor/workflow-editor.test-utils";
+import { PanelService } from 
"../../../../workspace/service/panel/panel.service";
 
 @Component({ selector: "texera-markdown-description", standalone: true, 
template: "" })
 class StubMarkdownDescriptionComponent {
@@ -440,3 +447,97 @@ describe("HubWorkflowDetailComponent", () => {
     });
   });
 });
+/**
+ * The suite above stubs the three child components out via 
`TestBed.overrideComponent`, and that
+ * is what puts `hub-workflow-detail.component.html` at 0% coverage: any 
override makes Angular
+ * re-JIT the component from its retained decorator metadata, and the 
re-compiled template has no
+ * source map back to the .html, so every binding still executes but none is 
attributed. The
+ * component's own .ts sits at 98% while its template reports 0/46 — only 
attribution loss produces
+ * that gap (see #7458).
+ *
+ * This block renders the component with its REAL children instead, which 
restores attribution. It
+ * keeps its own TestBed so the 32 tests above keep their mocked 
WorkflowActionService and their
+ * assertions on it; the real service is needed here only because the real 
editor injects
+ * DynamicSchemaService, which reads the graph's operator streams.
+ */
+describe("HubWorkflowDetailComponent rendered with its real children", () => {
+  let fixture: ComponentFixture<HubWorkflowDetailComponent>;
+
+  function render(opts: { isHub: boolean }): void {
+    TestBed.resetTestingModule();
+    TestBed.configureTestingModule({
+      imports: [
+        HubWorkflowDetailComponent,
+        NzIconModule.forChild([ArrowLeftOutline, EyeOutline, LikeOutline, 
UserOutline]),
+        DragDropModule,
+        ...workflowEditorTestImports,
+      ],
+      providers: [
+        ...workflowEditorTestProviders,
+        PanelService,
+        // The real markdown child renders <markdown>, which injects 
MarkdownService.
+        { provide: MarkdownService, useValue: { parse: (v: string) => v } },
+        // isHub is false when the wid arrives as modal data and true when it 
comes from the route,
+        // which is the switch the template's two halves hang off.
+        { provide: NZ_MODAL_DATA, useValue: opts.isHub ? undefined : { wid: 5 
} },
+        {
+          provide: ActivatedRoute,
+          useValue: { snapshot: { params: opts.isHub ? { id: "5" } : {} } },
+        },
+        { provide: Router, useValue: { navigateByUrl: vi.fn(), navigate: 
vi.fn() } },
+        {
+          provide: HubService,
+          useValue: {
+            getCounts: () => of([{ entityId: 5, entityType: 
EntityType.Workflow, counts: {} }]),
+            postView: () => of(7),
+            isLiked: () => of([]),
+            postLike: () => of(true),
+            postUnlike: () => of(true),
+            cloneWorkflow: () => of(99),
+          },
+        },
+        {
+          provide: WorkflowPersistService,
+          useValue: {
+            retrieveWorkflow: () => of({} as Workflow),
+            retrievePublicWorkflow: () => of({} as Workflow),
+            getOwnerName: () => of("owner"),
+            getWorkflowName: () => of("name"),
+            getWorkflowDescription: () => of("desc"),
+          },
+        },
+        { provide: NotificationService, useValue: { error: vi.fn(), success: 
vi.fn() } },
+        { provide: UserService, useClass: StubUserService },
+        ...commonTestProviders,
+      ],
+    });
+    fixture = TestBed.createComponent(HubWorkflowDetailComponent);
+    fixture.detectChanges();
+  }
+
+  it("renders the real editor and mini-map rather than stubs", () => {
+    // The point of this block: if these resolve to the stubbed selectors the 
template is
+    // re-JITed and its coverage silently goes to zero again.
+    render({ isHub: true });
+
+    const host = fixture.nativeElement as HTMLElement;
+    expect(host.querySelector("texera-workflow-editor")).not.toBeNull();
+    expect(host.querySelector("texera-mini-map")).not.toBeNull();
+  });
+
+  it("shows the back button when the id came from the route", () => {
+    // Asserted on the rendered DOM rather than on `isHub`: the class flag is 
set either way, so a
+    // class-state assertion cannot tell whether the template consults it.
+    render({ isHub: true });
+
+    expect((fixture.nativeElement as 
HTMLElement).querySelector(".go-back-button")).not.toBeNull();
+  });
+
+  it("hides the back button when the wid arrived as modal data", () => {
+    // The converse. Without it the `*ngIf` could be replaced by a constant 
and the positive case
+    // above would still pass.
+    render({ isHub: false });
+
+    expect((fixture.nativeElement as 
HTMLElement).querySelector(".go-back-button")).toBeNull();
+  });
+});

Reply via email to