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-5037-662c8cbe2ba4ed454305a27a6e57d46f501ee13f in repository https://gitbox.apache.org/repos/asf/texera.git
commit bf2f92c81bed8520d6421bdb4b820ca61667ca2a Author: Matthew B. <[email protected]> AuthorDate: Fri May 22 02:12:02 2026 -0700 test: enable child rendering in WorkspaceComponent spec (#5037) ### What changes were proposed in this PR? Drops the `<div #codeEditor>` template stub from `WorkspaceComponent`'s unit spec so the real `workspace.component.html` renders. Heavyweight children (workflow editor, panels, menu) are kept out of the test build by stripping the component's `imports`/`providers` and adding `CUSTOM_ELEMENTS_SCHEMA`, leaving the `<ng-template #codeEditor>` outlet free to wire a live `ViewContainerRef` into `CodeEditorService.vc`. A new `child rendering side effects` describe block asserts that the editor-lifecycle wiring runs end-to-end (the published outlet is a real `ViewContainerRef`, proven by `createEmbeddedView` being a function on it). ### Any related issues, documentation, or discussions? Closes: #5015 ### How was this PR tested? - `yarn test --include="src/app/workspace/component/workspace.component.spec.ts" --watch=false`: 20/20 pass (19 prior tests preserved, 1 new). - `yarn test --watch=false`: full suite 445 passed, 2 skipped, 2 todo (no regressions). - `yarn format:fix`: no rewrites. ### Was this PR authored or co-authored using generative AI tooling? Co-authored with Claude Opus 4.7 in compliance with ASF --------- Co-authored-by: Meng Wang <[email protected]> --- .../component/workspace.component.spec.ts | 39 ++++++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/workspace/component/workspace.component.spec.ts b/frontend/src/app/workspace/component/workspace.component.spec.ts index 0eaaf7f5fb..088ac06f3c 100644 --- a/frontend/src/app/workspace/component/workspace.component.spec.ts +++ b/frontend/src/app/workspace/component/workspace.component.spec.ts @@ -18,7 +18,7 @@ */ import { Location } from "@angular/common"; -import { NO_ERRORS_SCHEMA } from "@angular/core"; +import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from "@angular/core"; import { ComponentFixture, TestBed } from "@angular/core/testing"; import { HttpClientTestingModule } from "@angular/common/http/testing"; import { ActivatedRoute, Router } from "@angular/router"; @@ -130,12 +130,12 @@ describe("WorkspaceComponent", () => { routerMock = { navigate: vi.fn() }; locationMock = { go: vi.fn() }; - // TODO(#5015): drop this template override once CodeEditorComponent's - // own spec is fixed. Real child rendering would let us assert - // editor-lifecycle wiring; today we stub the host element so the - // heavyweight children don't compile in the test build. + // Drop the standalone component's child imports and allow unknown elements via + // CUSTOM_ELEMENTS_SCHEMA. The template still renders, so `<ng-template #codeEditor>` + // is wired up and the @ViewChild query resolves to a real ViewContainerRef, while + // the children's transitive dependencies stay out of the test build. TestBed.overrideComponent(WorkspaceComponent, { - set: { template: '<div #codeEditor class="stub-host"></div>', imports: [], providers: [] }, + set: { imports: [], providers: [], schemas: [CUSTOM_ELEMENTS_SCHEMA] }, }); await TestBed.configureTestingModule({ @@ -168,6 +168,8 @@ describe("WorkspaceComponent", () => { // ngOnDestroy clears the ViewContainerRef bound to `#codeEditor`. Tests that // exercise individual methods skip change detection, so the @ViewChild query // is never resolved; assign a stub to keep TestBed teardown from throwing. + // Tests that exercise `fixture.detectChanges()` will overwrite this with + // the live ViewContainerRef during ngAfterViewInit. component.codeEditorViewRef = { clear: vi.fn() } as any; } @@ -205,7 +207,12 @@ describe("WorkspaceComponent", () => { // retrieveWorkflow is consumed inside loadWorkflowWithId — keep it pending so // we can observe the pre-completion loading state. workflowPersistService.retrieveWorkflow.mockReturnValue(new Subject()); - fixture.detectChanges(); + // Drive the lifecycle hooks directly. Going through fixture.detectChanges() + // would re-render `[nzSpinning]="isLoading"` mid-cycle (isLoading flips from + // false to true inside ngAfterViewInit) and Angular's dev-mode stability + // check would throw NG0100. + component.ngOnInit(); + component.ngAfterViewInit(); expect(component.isLoading).toBe(true); expect(workflowActionService.disableWorkflowModification).toHaveBeenCalled(); }); @@ -337,6 +344,7 @@ describe("WorkspaceComponent", () => { describe("ngOnDestroy", () => { it("persists the workflow on destroy when the user is signed in and persist is enabled", async () => { await createFixture(); + fixture.detectChanges(); component.ngOnDestroy(); expect(workflowPersistService.persistWorkflow).toHaveBeenCalledWith(stubWorkflow); expect(workflowActionService.clearWorkflow).toHaveBeenCalled(); @@ -344,6 +352,7 @@ describe("WorkspaceComponent", () => { it("skips the persist call when the user is not signed in", async () => { await createFixture(); + fixture.detectChanges(); userService.isLogin.mockReturnValue(false); component.ngOnDestroy(); expect(workflowPersistService.persistWorkflow).not.toHaveBeenCalled(); @@ -359,4 +368,20 @@ describe("WorkspaceComponent", () => { expect(component.copilotEnabled).toBe(false); }); }); + + // Exercises the rendered template: the `<ng-template #codeEditor>` outlet is + // present, so the @ViewChild query resolves to a live ViewContainerRef and + // ngAfterViewInit can publish it to CodeEditorService. + describe("child rendering side effects", () => { + it("publishes the resolved ViewContainerRef to CodeEditorService.vc on view init", async () => { + codeEditorService.vc = undefined; + await createFixture(); + fixture.detectChanges(); + // createEmbeddedView is present on a real ViewContainerRef but not on the + // pre-fixture stub, so checking it distinguishes the resolved query from + // the placeholder. + expect(codeEditorService.vc).toBe(component.codeEditorViewRef); + expect(typeof codeEditorService.vc.createEmbeddedView).toBe("function"); + }); + }); });
