web-dev-qa-db-fra.com

Angular 4 persiste dans DOM pendant les tests Jasmine

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:

enter image description here

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?

26
Estus Flask

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);
});
26

Une solution plus concise:

afterEach(() => {
  element.remove()
});

element est fixture.debugElement.nativeElement

4
Darwayne

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.

2
marbug