unitarios unitarias test pruebas page change angular typescript karma-runner karma-jasmine

unitarias - Prueba del componente angular con error de cancelación de suscripción durante la limpieza del componente



test unitarios angular 5 (9)

Agregando a la respuesta de @David Brown, el código de abajo es lo que me funcionó.

.subscribe(res => { ... }, error => Observable.throw(error) )

Estoy probando un componente que suscriben parámetros de enrutador. Cada pase de prueba y todo funciona bien. Pero si miro en la consola, puedo ver un error:

Error durante la limpieza del componente ApplicationViewComponent localConsole. (Función anónima) @ context.js: 232

¿Sabes por qué ocurre esto?

Intenté quitar el unsubscribe() del método ngOnDestroy() y el error desaparece.

¿El karma / jazmín es compatible con unsubscribe() automáticamente?

Aquí está el componente y las pruebas.

Componente

import { Component, OnInit } from ''@angular/core''; import { ActivatedRoute } from ''@angular/router''; import { Subscription } from ''rxjs/Rx'' import { AppService } from ''app.service''; @Component({ selector: ''app-component'', templateUrl: ''./app.component.html'', styleUrls: [''./app.component.scss''] }) export class AppComponent implements OnInit { private routeSubscription: Subscription; // Main ID public applicationId: string; constructor( private route: ActivatedRoute, private _service: AppService ) { } ngOnInit() { this.routeSubscription = this.route.params.subscribe(params => { this.applicationId = params[''id'']; this.getDetails(); this.getList(); }); } getDetails() { this._service.getDetails(this.applicationId).subscribe( result => { console.log(result); }, error => { console.error(error); }, () => { console.info(''complete''); } ); } getList(notifyWhenComplete = false) { this._service.getList(this.applicationId).subscribe( result => { console.log(result); }, error => { console.error(error); }, () => { console.info(''complete''); } ); } ngOnDestroy() { this.routeSubscription.unsubscribe(); } }

Archivo de especificaciones de componentes

import { NO_ERRORS_SCHEMA } from ''@angular/core''; import { async, fakeAsync, ComponentFixture, TestBed, tick, inject } from ''@angular/core/testing''; import { RouterTestingModule } from ''@angular/router/testing''; import { HttpModule } from ''@angular/http''; import { Observable } from ''rxjs/Observable''; import { Router, ActivatedRoute } from ''@angular/router''; // Components import { AppComponent } from ''./app.component''; // Service import { AppService } from ''app.service''; import { AppServiceStub } from ''./app.service.stub''; let comp: AppComponent; let fixture: ComponentFixture<AppComponent>; let service: AppService; let expectedApplicationId = ''abc123''; describe(''AppComponent'', () => { beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [AppComponent], imports: [RouterTestingModule, HttpModule], providers: [ FormBuilder, { provide: ActivatedRoute, useValue: { params: Observable.of({id: expectedApplicationId}) } }, { provide: AppService, useClass: AppServiceStub } ], schemas: [ NO_ERRORS_SCHEMA ] }) .compileComponents(); })); tests(); }); function tests() { beforeEach(() => { fixture = TestBed.createComponent(AppComponent); comp = fixture.componentInstance; service = TestBed.get(AppService); }); /* * COMPONENT BEFORE INIT */ it(`should be initialized`, () => { expect(fixture).toBeDefined(); expect(comp).toBeDefined(); }); /* * COMPONENT INIT */ it(`should retrieve param id from ActivatedRoute`, async(() => { fixture.detectChanges(); expect(comp.applicationId).toEqual(expectedApplicationId); })); it(`should get the details after ngOnInit`, async(() => { spyOn(comp, ''getDetails''); fixture.detectChanges(); expect(comp.getDetails).toHaveBeenCalled(); })); it(`should get the list after ngOnInit`, async(() => { spyOn(comp, ''getList''); fixture.detectChanges(); expect(comp.getList).toHaveBeenCalled(); })); }

service.stub

import { Observable } from ''rxjs/Observable''; export class AppServiceStub { getList(id: string) { return Observable.from([ { id: "7a0c6610-f59b-4cd7-b649-1ea3cf72347f", name: "item 1" }, { id: "f0354c29-810e-43d8-8083-0712d1c412a3", name: "item 2" }, { id: "2494f506-009a-4af8-8ca5-f6e6ba1824cb", name: "item 3" } ]); } getDetails(id: string) { return Observable.from([ { id: id, name: "detailed item 1" } ]); } }


Así que mi situación fue similar, pero no exactamente igual: solo estoy poniendo esto aquí en caso de que alguien más lo encuentre útil. Cuando la unidad de pruebas con Jamine / Karma estaba recibiendo

''ERROR: ''Error during cleanup of component'',''

Resulta que fue porque no estaba manejando correctamente mis observables y no tenían una función de error en ellos. Así que la solución fue agregar una función de error:

this.entityService.subscribe((items) => { ///Do work }, error => { this.errorEventBus.throw(error); });


Bueno, en mi caso el error estaba en la plantilla. Se produjo un error en el componente secundario ngDestroy, que no se destruyó porque estaba intentando establecer una propiedad de solo lectura. Valdría la pena que dediques tiempo a comprobar los componentes de tu hijo si se destruyen correctamente.


Debe refactorizar su método ngOnDestroy de la siguiente manera:

ngOnDestroy() { if ( this.routeSubscription) this.routeSubscription.unsubscribe(); }


En mi caso, destruir el componente después de cada prueba resolvió el problema. Así que podrías intentar agregar esto a tu función de descripción:

afterEach(() => { fixture.destroy(); })


Estoy en una situación similar en la que quiero probar una función en mi componente fuera del contexto del componente mismo.

Esto es lo que funcionó para mí:

afterEach(() => { spyOn(component, ''ngOnDestroy'').and.callFake(() => { }); fixture.destroy(); });


La solución aceptada no es óptima, resuelve el hecho de que la prueba no está configurada correctamente.

El mensaje de error "Error durante la limpieza del componente" ngOnDestroy() porque cuando se llama a ngOnDestroy() , esta this.routeSubscription no está definida. Esto sucede porque ngOnInit() nunca se invocó, lo que significa que nunca se suscribió a la ruta. Como se describe en el tutorial de prueba Angular , el componente no se inicializa completamente hasta que llama a fixture.detectChanges() la primera vez.

Por lo tanto, la solución correcta es agregar fixture.detectChanges() a su bloque beforeEach() justo después de createComponent al createComponent . Se puede agregar en cualquier momento después de crear el accesorio. Si lo hace, se asegurará de que el componente esté completamente inicializado, de esa manera la limpieza del componente también se comportará como se espera.


Para mí, lo que solucionó este error estaba dentro del ngOnDestroy de mi componente, envolví el envío de mi tienda y mi anulación de suscripción en una captura de prueba.

ngOnDestroy(): void { try { this.store.dispatch(new foo.Bar(this.testThing())); if(this.fooBarSubscription) { this.fooBarSubscription.unsubscribe(); } } catch (error) { this.store.dispatch(new foo.Bar(this.testThing())); } }


Tienes que hacer 2 cosas, para solucionar este error.

1- agregar fixture.detectChanges (); en beforeEach ()
2: debe agregar a continuación, para que el componente esté claro.

afterEach(() => { fixture.destroy(); });