web-dev-qa-db-fra.com

Angular2 Inject ElementRef dans le test unitaire

J'essaie de tester un composant qui reçoit une référence à ElementRef via DI.

import { Component, OnInit, ElementRef } from '@angular/core';

@Component({
  selector: 'cp',
  templateUrl: '...',
  styleUrls: ['...']
})
export class MyComponent implements OnInit {

  constructor(private elementRef: ElementRef) {
    //stuffs
  }

  ngAfterViewInit() {
    // things
  }

  ngOnInit() {
  }
}

et le test:

import {
  beforeEach,
  beforeEachProviders,
  describe,
  expect,
  it,
  inject,
} from '@angular/core/testing';
import { ComponentFixture, TestComponentBuilder } from '@angular/compiler/testing';
import { Component, Renderer, ElementRef } from '@angular/core';
import { By } from '@angular/platform-browser';

describe('Component: My', () => {
  let builder: TestComponentBuilder;

  beforeEachProviders(() => [MyComponent]);
  beforeEach(inject([TestComponentBuilder], function (tcb: TestComponentBuilder) {
    builder = tcb;
  }));

  it('should inject the component', inject([MyComponent],
      (component: MyComponent) => {
    expect(component).toBeTruthy();
  }));

  it('should create the component', inject([], () => {
    return builder.createAsync(MyComponentTestController)
      .then((fixture: ComponentFixture<any>) => {
        let query = fixture.debugElement.query(By.directive(MyComponent));
        expect(query).toBeTruthy();
        expect(query.componentInstance).toBeTruthy();
      });
  }));
});

@Component({
  selector: 'test',
  template: `
    <cp></cp>
  `,
  directives: [MyComponent]
})
class MyTestController {
}

Le composant et le plan de test ont été générés par Angular-cli. Maintenant, je ne peux pas déterminer quel fournisseur, le cas échéant, je devrais ajouter dans le beforeEachProviders pour que l'injection d'ElementRef réussisse. Lorsque j'exécute ng test, J'ai obtenu Error: No provider for ElementRef! (MyComponent -> ElementRef).

20
Mathieu Nls

On Angular 2.2.3:

export class MockElementRef extends ElementRef {}

Puis dans le test:

beforeEach(async(() => {
  TestBed.configureTestingModule({
    providers: [
      //more providers
      { provide: ElementRef, useClass: MockElementRef }
    ]
  }).compileComponents();
}));
12
Gilad S

Je rencontre Can't resolve all parameters for ElementRef: (?) Erreur lors de l'utilisation de la maquette de @ gilad-s dans angular 2.4

Modification de la classe fictive pour:

export class MockElementRef extends ElementRef {
  constructor() { super(null); }
}

résout l'erreur de test.

Lecture à partir du code source angular ici: https://github.com/angular/angular/blob/master/packages/core/testing/src/component_fixture.ts#L17 -L6 L'élémentRef du luminaire n'est pas créé à partir de l'injection factice. Et dans le développement normal, nous ne fournissons pas explicitement ElementRef lors de l'injection dans un composant. Je pense que TestBed devrait permettre le même comportement.

25
Northern

Pour injecter un ElementRef:

  1. Créer une maquette
class MockElementRef implements ElementRef {
  nativeElement = {};
}
  1. Fournir la maquette au composant testé
beforeEachProviders(() => [Component, provide(ElementRef, { useValue: new MockElementRef() })]);

EDIT: Cela fonctionnait sur rc4. La version finale a introduit des changements de rupture et invalide cette réponse.

7
Mathieu Nls

Un bon moyen consiste à utiliser spyOn et spyOnProperty pour instantanément se moquer des méthodes et des propriétés selon les besoins. spyOnProperty attend 3 propriétés et vous devez passer get ou set comme troisième propriété. spyOn fonctionne avec la classe et la méthode et renvoie la valeur requise.

Exemple

const div = fixture.debugElement.query(By.css('.Ellipsis-overflow'));
// now mock properties
spyOnProperty(div.nativeElement, 'clientWidth', 'get').and.returnValue(1400);
spyOnProperty(div.nativeElement, 'scrollWidth', 'get').and.returnValue(2400);

Ici, je configure le get de clientWidth de div.nativeElement objet.

1
Aniruddha Das