diff --git a/projects/testing-library/src/lib/testing-library.ts b/projects/testing-library/src/lib/testing-library.ts index 1bc5a4e6..1a213318 100644 --- a/projects/testing-library/src/lib/testing-library.ts +++ b/projects/testing-library/src/lib/testing-library.ts @@ -31,7 +31,7 @@ export async function render( renderOptions: RenderComponentOptions | RenderDirectiveOptions = {}, ): Promise> { const { - detectChanges = true, + detectChanges: detectChangesOnRender = true, declarations = [], imports = [], providers = [], @@ -42,12 +42,12 @@ export async function render( componentProperties = {}, componentProviders = [], excludeComponentDeclaration = false, - routes + routes, } = renderOptions as RenderDirectiveOptions; TestBed.configureTestingModule({ declarations: addAutoDeclarations(sut, { declarations, excludeComponentDeclaration, template, wrapper }), - imports: addAutoImports({imports, routes}), + imports: addAutoImports({ imports, routes }), providers: [...providers], schemas: [...schemas], }); @@ -66,15 +66,24 @@ export async function render( await TestBed.compileComponents(); - if (detectChanges) { - fixture.detectChanges(); + let isAlive = true; + fixture.componentRef.onDestroy(() => (isAlive = false)); + + function detectChanges() { + if (isAlive) { + fixture.detectChanges(); + } + } + + if (detectChangesOnRender) { + detectChanges(); } const eventsWithDetectChanges = Object.keys(fireEvent).reduce( (events, key) => { events[key] = (element: HTMLElement, options?: {}) => { const result = fireEvent[key](element, options); - fixture.detectChanges(); + detectChanges(); return result; }; return events; @@ -93,8 +102,8 @@ export async function render( const href = typeof elementOrPath === 'string' ? elementOrPath : elementOrPath.getAttribute('href'); let result; - await zone.run(() => result = router.navigate([basePath + href])); - fixture.detectChanges(); + await zone.run(() => (result = router.navigate([basePath + href]))); + detectChanges(); return result; } const debugElement = fixture.debugElement.query(By.directive(sut)); @@ -104,7 +113,7 @@ export async function render( debugElement, container: fixture.nativeElement, debug: (element = fixture.nativeElement) => console.log(prettyDOM(element)), - detectChanges: () => fixture.detectChanges(), + detectChanges, ...getQueriesForElement(fixture.nativeElement, queries), ...eventsWithDetectChanges, type: createType(eventsWithDetectChanges), diff --git a/projects/testing-library/tests/detect-changes.spec.ts b/projects/testing-library/tests/detect-changes.spec.ts index 40f68812..7a4fbf15 100644 --- a/projects/testing-library/tests/detect-changes.spec.ts +++ b/projects/testing-library/tests/detect-changes.spec.ts @@ -40,4 +40,13 @@ describe('detectChanges', () => { expect(getByTestId('button').innerHTML).toBe('Button updated after 400ms'); })); + + test('does not throw on a destroyed fixture', async () => { + const { getByTestId, type, fixture } = await render(FixtureComponent, { imports: [ReactiveFormsModule] }); + + fixture.destroy(); + + type(getByTestId('input'), 'What a great day!'); + expect(getByTestId('button').innerHTML).toBe('Button'); + }); }); diff --git a/projects/testing-library/tests/fire-event.spec.ts b/projects/testing-library/tests/fire-event.spec.ts new file mode 100644 index 00000000..43aaed13 --- /dev/null +++ b/projects/testing-library/tests/fire-event.spec.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { render } from '../src/public_api'; + +@Component({ + selector: 'fixture', + template: ` + + `, +}) +class FixtureComponent {} + +test('does not call detect changes when fixture is destroyed', async () => { + const component = await render(FixtureComponent); + + component.fixture.destroy(); + + // should otherwise throw + component.input(component.getByTestId('input'), { target: { value: 'Bonjour' } }); + component.type(component.getByTestId('input'), 'Alles klar'); +});