角度2 - 测试路线参数的变化

时间:2016-10-26 12:54:18

标签: angular jasmine angular2-routing angular2-testing angular2-observables

我在角度2中有一个组件响应路径参数的变化(组件不会从头开始重新加载,因为我们没有移出主路线。这里是组件代码:

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

这适用于待遇,_pageToShow适用于导航。

我试图测试路线变化的行为(所以可观察的第二个触发器,但它拒绝为我工作。)这是我的尝试:

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 个答案:

答案 0 :(得分:23)

首先,您应该使用Subject而不是Observable。 observable只能订阅一次。所以它只会发出第一组参数。使用Subject,您可以继续发出项目,单个订阅将继续获取它们。

let params: Subject<Params>;

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

然后在您的测试中,只需使用params.next(newValue)发出新值。

其次,您需要确保致电tick()。这就是fakeAsync的工作原理。您可以控制异步任务解析。由于可观察为asychrounous,在我们发送事件的那一刻,它不会同步到达订户。所以我们需要强制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');
  }));
});

答案 1 :(得分:2)

我更喜欢像这样this.route.snapshot.params['type']

从ActivatedRouteSnapshot获取路由参数和数据

如果使用相同的方法,则可以像这样进行测试

1)在您的测试提供者中

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

2)在您的测试规范中

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