Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions frontend/src/app/workspace/component/workspace.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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();
});
Expand Down Expand Up @@ -337,13 +344,15 @@ 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();
});

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();
Expand All @@ -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");
});
});
});
Loading