Skip to content

Commit dbad080

Browse files
authored
Merge branch 'main' into refactor/shortenURL
2 parents adef119 + bf2f92c commit dbad080

1 file changed

Lines changed: 32 additions & 7 deletions

File tree

frontend/src/app/workspace/component/workspace.component.spec.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
import { Location } from "@angular/common";
21-
import { NO_ERRORS_SCHEMA } from "@angular/core";
21+
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from "@angular/core";
2222
import { ComponentFixture, TestBed } from "@angular/core/testing";
2323
import { HttpClientTestingModule } from "@angular/common/http/testing";
2424
import { ActivatedRoute, Router } from "@angular/router";
@@ -130,12 +130,12 @@ describe("WorkspaceComponent", () => {
130130
routerMock = { navigate: vi.fn() };
131131
locationMock = { go: vi.fn() };
132132

133-
// TODO(#5015): drop this template override once CodeEditorComponent's
134-
// own spec is fixed. Real child rendering would let us assert
135-
// editor-lifecycle wiring; today we stub the host element so the
136-
// heavyweight children don't compile in the test build.
133+
// Drop the standalone component's child imports and allow unknown elements via
134+
// CUSTOM_ELEMENTS_SCHEMA. The template still renders, so `<ng-template #codeEditor>`
135+
// is wired up and the @ViewChild query resolves to a real ViewContainerRef, while
136+
// the children's transitive dependencies stay out of the test build.
137137
TestBed.overrideComponent(WorkspaceComponent, {
138-
set: { template: '<div #codeEditor class="stub-host"></div>', imports: [], providers: [] },
138+
set: { imports: [], providers: [], schemas: [CUSTOM_ELEMENTS_SCHEMA] },
139139
});
140140

141141
await TestBed.configureTestingModule({
@@ -168,6 +168,8 @@ describe("WorkspaceComponent", () => {
168168
// ngOnDestroy clears the ViewContainerRef bound to `#codeEditor`. Tests that
169169
// exercise individual methods skip change detection, so the @ViewChild query
170170
// is never resolved; assign a stub to keep TestBed teardown from throwing.
171+
// Tests that exercise `fixture.detectChanges()` will overwrite this with
172+
// the live ViewContainerRef during ngAfterViewInit.
171173
component.codeEditorViewRef = { clear: vi.fn() } as any;
172174
}
173175

@@ -205,7 +207,12 @@ describe("WorkspaceComponent", () => {
205207
// retrieveWorkflow is consumed inside loadWorkflowWithId — keep it pending so
206208
// we can observe the pre-completion loading state.
207209
workflowPersistService.retrieveWorkflow.mockReturnValue(new Subject());
208-
fixture.detectChanges();
210+
// Drive the lifecycle hooks directly. Going through fixture.detectChanges()
211+
// would re-render `[nzSpinning]="isLoading"` mid-cycle (isLoading flips from
212+
// false to true inside ngAfterViewInit) and Angular's dev-mode stability
213+
// check would throw NG0100.
214+
component.ngOnInit();
215+
component.ngAfterViewInit();
209216
expect(component.isLoading).toBe(true);
210217
expect(workflowActionService.disableWorkflowModification).toHaveBeenCalled();
211218
});
@@ -337,13 +344,15 @@ describe("WorkspaceComponent", () => {
337344
describe("ngOnDestroy", () => {
338345
it("persists the workflow on destroy when the user is signed in and persist is enabled", async () => {
339346
await createFixture();
347+
fixture.detectChanges();
340348
component.ngOnDestroy();
341349
expect(workflowPersistService.persistWorkflow).toHaveBeenCalledWith(stubWorkflow);
342350
expect(workflowActionService.clearWorkflow).toHaveBeenCalled();
343351
});
344352

345353
it("skips the persist call when the user is not signed in", async () => {
346354
await createFixture();
355+
fixture.detectChanges();
347356
userService.isLogin.mockReturnValue(false);
348357
component.ngOnDestroy();
349358
expect(workflowPersistService.persistWorkflow).not.toHaveBeenCalled();
@@ -359,4 +368,20 @@ describe("WorkspaceComponent", () => {
359368
expect(component.copilotEnabled).toBe(false);
360369
});
361370
});
371+
372+
// Exercises the rendered template: the `<ng-template #codeEditor>` outlet is
373+
// present, so the @ViewChild query resolves to a live ViewContainerRef and
374+
// ngAfterViewInit can publish it to CodeEditorService.
375+
describe("child rendering side effects", () => {
376+
it("publishes the resolved ViewContainerRef to CodeEditorService.vc on view init", async () => {
377+
codeEditorService.vc = undefined;
378+
await createFixture();
379+
fixture.detectChanges();
380+
// createEmbeddedView is present on a real ViewContainerRef but not on the
381+
// pre-fixture stub, so checking it distinguishes the resolved query from
382+
// the placeholder.
383+
expect(codeEditorService.vc).toBe(component.codeEditorViewRef);
384+
expect(typeof codeEditorService.vc.createEmbeddedView).toBe("function");
385+
});
386+
});
362387
});

0 commit comments

Comments
 (0)