From ee892ee294b2fc5ab6186d8434ec5d79a66165e2 Mon Sep 17 00:00:00 2001 From: Andrew Kushnir Date: Tue, 14 Nov 2023 15:12:01 -0800 Subject: [PATCH] fix(core): reset cached scope for components that were overridden using TestBed (#52916) Currently, when a component is overriden using `TestBed.overrideComponent`, Angular retains calculated scope for that component (a set of components and directives used within a component). This may cause stale information to be used in tests in some cases. This commit updates the logic to reset overridden component scope, so it gets re-computed during the next invocation. Resolves #52817. PR Close #52916 --- packages/core/test/test_bed_spec.ts | 50 +++++++++++++++++++ .../core/testing/src/test_bed_compiler.ts | 3 ++ 2 files changed, 53 insertions(+) diff --git a/packages/core/test/test_bed_spec.ts b/packages/core/test/test_bed_spec.ts index 9fef0b46f53..2dd3c1d9add 100644 --- a/packages/core/test/test_bed_spec.ts +++ b/packages/core/test/test_bed_spec.ts @@ -175,6 +175,56 @@ describe('TestBed with Standalone types', () => { TestBed.resetTestingModule(); }); + it('should override dependencies of standalone components', () => { + @Component({ + selector: 'dep', + standalone: true, + template: 'main dep', + }) + class MainDep { + } + + @Component({ + selector: 'dep', + standalone: true, + template: 'mock dep', + }) + class MockDep { + } + + @Component({ + selector: 'app-root', + standalone: true, + imports: [MainDep], + template: '', + }) + class AppComponent { + } + + TestBed.configureTestingModule({imports: [AppComponent]}); + + let fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + + // No overrides defined, expecting main dependency to be used. + expect(fixture.nativeElement.innerHTML).toBe('main dep'); + + // Emulate an end of a test. + TestBed.resetTestingModule(); + + // Emulate the start of a next test, make sure previous overrides + // are not persisted across tests. + TestBed.configureTestingModule({imports: [AppComponent]}); + TestBed.overrideComponent(AppComponent, {set: {imports: [MockDep]}}); + + fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + + // Main dependency was overridden, expect to see a mock. + expect(fixture.nativeElement.innerHTML).toBe('mock dep'); + }); + + it('should override providers on standalone component itself', () => { const A = new InjectionToken('A'); diff --git a/packages/core/testing/src/test_bed_compiler.ts b/packages/core/testing/src/test_bed_compiler.ts index 1039a778221..4c2a7c87b22 100644 --- a/packages/core/testing/src/test_bed_compiler.ts +++ b/packages/core/testing/src/test_bed_compiler.ts @@ -396,6 +396,9 @@ export class TestBedCompiler { } this.maybeStoreNgDef(NG_COMP_DEF, declaration); + if (USE_RUNTIME_DEPS_TRACKER_FOR_JIT) { + depsTracker.clearScopeCacheFor(declaration); + } compileComponent(declaration, metadata); }); this.pendingComponents.clear();