web-dev-qa-db-ja.com

Angular 2-ルートパラメータの変更をテストします

angular 2にコンポーネントがあります。これはルートパラメータの変更に応答します(メインルートから移動しないため、コンポーネントは最初から再読み込みされません。コンポーネントコードは次のとおりです:

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

これは機能し、__pageToShow_はナビゲーションで適切に設定されます。

ルートの変更時の動作をテストしようとしています(つまり、オブザーバブルの2番目のトリガーですが、私のために機能することを拒否しています)。これが私の試みです。

_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");
}));
_

しかし、これを実行すると_TypeError: Cannot read property 'subscribe' of undefined_例外がスローされます。 fixture.detectChanges();行なしで実行すると、2番目の期待が失敗するため失敗します。

15
Stu

まず、Subjectの代わりにObservableを使用する必要があります。オブザーバブルは1回だけサブスクライブされます。そのため、最初のパラメータセットのみを発行します。 Subjectを使用すると、アイテムを放出し続けることができ、単一のサブスクリプションはそれらを取得し続けます。

_let params: Subject<Params>;

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

次に、テストでparams.next(newValue)を使用して新しい値を出力します。

次に、必ずtick()を呼び出す必要があります。これがfakeAsyncの仕組みです。非同期タスク解決を制御します。観測可能なのは無秩序なので、イベントを送信した瞬間に、サブスクライバーに同期的に到達しません。したがって、tick()を使用して同期動作を強制する必要があります

以下は完全なテストです(Subjectは_'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');
  }));
});
_
25
Paul Samsotha

私はこのようにActivatedRouteSnapshotからルートパラメータとデータを取得することを好みますthis.route.snapshot.params['type']

同じように使えば、このようにテストできます

1)テストプロバイダー

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

2)テスト仕様

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