Lors de l'exécution de Jasmine dans un navigateur réel, j'ai remarqué que le composant fixture TestBed
n'est pas détruit dans DOM et persiste après la fin des tests:
Voici un composant testé:
@Component({
selector: 'test-app',
template: `<div>Test</div>`,
})
class Test {}
Et un test ( plunk ).
let component;
let fixture;
let element;
beforeAll(() => {
TestBed.resetTestEnvironment();
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
});
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [Test],
})
.compileComponents();
fixture = TestBed.createComponent(Test);
component = fixture.componentInstance;
element = fixture.debugElement.query(By.css('div')).nativeElement;
fixture.detectChanges();
});
afterEach(() => {
fixture.destroy();
});
it('should compile Test', () => {
expect(element).toBeTruthy();
});
Pourquoi l'instance de composant Test
n'est pas supprimée du DOM et comment cela devrait-il être corrigé?
Pourquoi les composants de luminaire sont-ils ajoutés au DOM? Peuvent-ils être détachés du DOM comme $rootElement
dans AngularJS?
Je pense que Angular ne le supprime pas automatiquement pour vous aider à obtenir plus de détails sur l'exécution de votre test. Pour le supprimer, vous utilisez simplement afterEach:
beforeEach(() => {
fixture = TestBed.createComponent(MyComponent);
comp = fixture.componentInstance;
debugElement = fixture.debugElement;
element = debugElement.nativeElement;
});
afterEach(() => {
document.body.removeChild(element);
});
Une solution plus concise:
afterEach(() => {
element.remove()
});
Où element
est fixture.debugElement.nativeElement
Veuillez jeter un œil aux problèmes suivants:
1) Tout d'abord, vous appelez
fixture.destroy();
in afterEach, il est donc appelé après la section it. C'est à dire. dans it le luminaire de la section n'est toujours pas détruit
2) par quel code détectez-vous que cet élément est toujours présent dans DOM? D'un autre point de vue: pourquoi cet élément devrait être supprimé par jasmine/browser (quelle raison devrait faire jasmine/browser)? Je pourrais suggérer les cas d'utilisation suivants:
2.1) un composant est utilisé dans un autre et doit être créé/détruit par un changement. C'est à dire. ngIf ou ngSwitchCase:
<parent-component>
<child-component *ngIf="someChangeInComponent1"></child-component>
</parent-component>
ou
<parent-component [ngSwitch]="type">
<child-component *ngSwitchCase="'something'"></child-component>
</parent-component>
2.2) le routage est modifié (mais ce n'est pas un sujet pour les tests unitaires AFAIK)
3) le code actuel ne reçoit la référence à l'élément DOM qu'une seule fois. Devrait être quelque chose comme:
beforeEach(() => {
...
element = ...
});
it('...', () => {
...
fixture.detectChanges();
element = ... // try to get element again <--------------------- here
})
4) si vous essayez de trouver des erreurs comme ngOnDestroy () est défini mais implémente OnDestroy n'est pas utilisé alors c'est plus un sujet pour npm run lint = que pour les tests unitaires (veuillez consulter se-life-cycle-interface in tslint.json). Après avoir exécuté npm run lint vous verrez juste:
Implement lifecycle hook interface OnDestroy for method ngOnDestroy in class ...
C'est une bonne pratique de ne pas avoir d'erreurs non seulement pour le test unitaire mais aussi pour tslint.