fix(core): reset tView
between tests in Ivy TestBed (#38659)
`tView` that is stored on a component def contains information about directives and pipes that are available in the scope of this component. Patching component scope causes `tView` to be updated. Prior to this commit, the `tView` information was not restored/reset in case component class is not declared in the `declarations` field while calling `TestBed.configureTestingModule`, thus causing `tView` to be reused between tests (thus preserving scopes information between tests). This commit updates TestBed logic to preserve `tView` value before applying scope changes and reset it back to the previous state between tests. Closes #38600. PR Close #38659
This commit is contained in:
parent
50f4d8a1ce
commit
44bb85ade4
@ -1126,6 +1126,63 @@ describe('TestBed', () => {
|
||||
expect(SomePipe.hasOwnProperty('ɵpipe')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should cleanup scopes (configured via `TestBed.configureTestingModule`) between tests',
|
||||
() => {
|
||||
@Component({
|
||||
selector: 'child',
|
||||
template: 'Child comp',
|
||||
})
|
||||
class ChildCmp {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'root',
|
||||
template: '<child></child>',
|
||||
})
|
||||
class RootCmp {
|
||||
}
|
||||
|
||||
// Case #1: `RootCmp` and `ChildCmp` are both included in the `declarations` field of
|
||||
// the testing module, so `ChildCmp` is in the scope of `RootCmp`.
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [RootCmp, ChildCmp],
|
||||
});
|
||||
|
||||
let fixture = TestBed.createComponent(RootCmp);
|
||||
fixture.detectChanges();
|
||||
|
||||
let childCmpInstance = fixture.debugElement.query(By.directive(ChildCmp));
|
||||
expect(childCmpInstance.componentInstance).toBeAnInstanceOf(ChildCmp);
|
||||
expect(fixture.nativeElement.textContent).toBe('Child comp');
|
||||
|
||||
TestBed.resetTestingModule();
|
||||
|
||||
// Case #2: the `TestBed.configureTestingModule` was not invoked, thus the `ChildCmp`
|
||||
// should not be available in the `RootCmp` scope and no child content should be
|
||||
// rendered.
|
||||
fixture = TestBed.createComponent(RootCmp);
|
||||
fixture.detectChanges();
|
||||
|
||||
childCmpInstance = fixture.debugElement.query(By.directive(ChildCmp));
|
||||
expect(childCmpInstance).toBeNull();
|
||||
expect(fixture.nativeElement.textContent).toBe('');
|
||||
|
||||
TestBed.resetTestingModule();
|
||||
|
||||
// Case #3: `ChildCmp` is included in the `declarations` field, but `RootCmp` is not,
|
||||
// so `ChildCmp` is NOT in the scope of `RootCmp` component.
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ChildCmp],
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(RootCmp);
|
||||
fixture.detectChanges();
|
||||
|
||||
childCmpInstance = fixture.debugElement.query(By.directive(ChildCmp));
|
||||
expect(childCmpInstance).toBeNull();
|
||||
expect(fixture.nativeElement.textContent).toBe('');
|
||||
});
|
||||
|
||||
it('should clean up overridden providers for modules that are imported more than once',
|
||||
() => {
|
||||
@Injectable()
|
||||
|
@ -379,6 +379,11 @@ export class R3TestBedCompiler {
|
||||
const moduleScope = getScopeOfModule(moduleType);
|
||||
this.storeFieldOfDefOnType(componentType, NG_COMP_DEF, 'directiveDefs');
|
||||
this.storeFieldOfDefOnType(componentType, NG_COMP_DEF, 'pipeDefs');
|
||||
// `tView` that is stored on component def contains information about directives and pipes
|
||||
// that are in the scope of this component. Patching component scope will cause `tView` to be
|
||||
// changed. Store original `tView` before patching scope, so the `tView` (including scope
|
||||
// information) is restored back to its previous/original state before running next test.
|
||||
this.storeFieldOfDefOnType(componentType, NG_COMP_DEF, 'tView');
|
||||
patchComponentDefWithScope((componentType as any).ɵcmp, moduleScope);
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user