web-dev-qa-db-fra.com

Angular 2 - test de changement de paramètres de route

J'ai un composant dans angular 2 qui répond aux changements dans les paramètres de route (le composant ne se recharge pas à partir de zéro car nous ne sortons pas de la route principale. Voici le code du composant:

export class MyComponent{
    ngOnInit() {
        this._routeInfo.params.forEach((params: Params) => {
            if (params['area']){
                this._pageToShow =params['area'];
            }
        });
    }
}

Cela fonctionne avec un traitement et _pageToShow est défini de manière appropriée sur la navigation.

J'essaie de tester le comportement sur une modification de la route (donc un deuxième déclencheur de l'observable, mais il refuse de travailler pour moi.) Voici ma tentative: 

it('sets PageToShow to new area if params.area is changed', fakeAsync(() => {
    let routes : Params[] = [{ 'area': "Terry" }];
    TestBed.overrideComponent(MyComponent, {
        set: {
            providers: [{ provide: ActivatedRoute,
                useValue: { 'params': Observable.from(routes)}}]
        }
    });

    let fixture = TestBed.createComponent(MyComponent);
    let comp = fixture.componentInstance;
    let route: ActivatedRoute = fixture.debugElement.injector.get(ActivatedRoute);
    comp.ngOnInit();

    expect(comp.PageToShow).toBe("Terry");
    routes.splice(2,0,{ 'area': "Billy" });

    fixture.detectChanges();
    expect(comp.PageToShow).toBe("Billy");
}));

Mais cela génère une exception TypeError: Cannot read property 'subscribe' of undefined lorsque je l'exécute. Si je l'exécute sans la ligne fixture.detectChanges();, il échoue, comme la deuxième attente échoue.

14
Stu

Premièrement, vous devriez utiliser une Subject au lieu d'une Observable. L'observable n'est souscrit qu'une seule fois. Donc, il n’émettra que le premier ensemble de paramètres. Avec une Subject, vous pouvez continuer à émettre des éléments, et l'abonnement unique continuera à les obtenir.

let params: Subject<Params>;

beforeEach(() => {
  params = new Subject<Params>();
  TestBed.configureTestingModule({
    providers: [
      { provide: ActivatedRoute, useValue: { params: params }}
    ]
  })
})

Ensuite, dans votre test, émettez simplement de nouvelles valeurs avec params.next(newValue).

Deuxièmement, vous devez vous assurer d’appeler tick(). C’est ainsi que fonctionne fakeAsync. Vous contrôlez la résolution des tâches asynchrones. Comme l’observable est asynchrone, au moment où nous envoyons l’événement, il ne sera pas transmis à l’abonné de manière synchrone. Nous devons donc forcer le comportement synchrone avec tick()

Voici un test complet (Subject est importé de 'rxjs/Subject')

@Component({
  selector: 'test',
  template: `
  `
})
export class TestComponent implements OnInit {

  _pageToShow: string;

  constructor(private _route: ActivatedRoute) {
  }

  ngOnInit() {
    this._route.params.forEach((params: Params) => {
      if (params['area']) {
        this._pageToShow = params['area'];
      }
    });
  }
}

describe('TestComponent', () => {
  let fixture: ComponentFixture<TestComponent>;
  let component: TestComponent;
  let params: Subject<Params>;

  beforeEach(() => {
    params = new Subject<Params>();
    TestBed.configureTestingModule({
      declarations: [ TestComponent ],
      providers: [
        { provide: ActivatedRoute, useValue: { params: params } }
      ]
    });
    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
  });

  it('should change on route param change', fakeAsync(() => {
    // this calls ngOnInit and we subscribe
    fixture.detectChanges();

    params.next({ 'area': 'Terry' });

    // tick to make sure the async observable resolves
    tick();

    expect(component._pageToShow).toBe('Terry');

    params.next({ 'area': 'Billy' });
    tick();

    expect(component._pageToShow).toBe('Billy');
  }));
});
21
Paul Samsotha

Je préfère obtenir les paramètres de route et les données de ActivatedRouteSnapshot comme ceci this.route.snapshot.params['type']

Si vous utilisez la même manière, vous pouvez le tester comme ceci

1) chez vos prestataires de test

{provide: ActivatedRoute, useValue: {snapshot: { params: { type: '' } }}}

2) dans vos spécifications de test

it('should...', () => {
   component.route.snapshot.params['type'] = 'test';
   fixture.detectChanges();
   // ...
});
1
Victor Bredihin