Javascript Jasmine:用事件测试可观测值

Javascript Jasmine:用事件测试可观测值,javascript,testing,typescript,jasmine,angular,Javascript,Testing,Typescript,Jasmine,Angular,我正在尝试测试angular2应用程序。我有一个登录表单,它使用一个observable将数据发送到后端: doLogin() { this.usersService.login(this.model) .subscribe((data) => { console.log("In observable: " + data.isSuccess); if (!data.isSuccess) {

我正在尝试测试angular2应用程序。我有一个登录表单,它使用一个observable将数据发送到后端:

doLogin() {
    this.usersService.login(this.model)
        .subscribe((data) => {
            console.log("In observable: " + data.isSuccess);
            if (!data.isSuccess) {
                this.alerts.push({});
            }
        });
}
在测试中,我在服务函数上添加了一个spy,它返回observable,以便组件可以处理它:

 usersService.login.and.returnValue(Observable.of(
    <LoginResponse>{
        isSuccess: true
    }));
它工作正常。不幸的是,当我检查测试中是否调用了usersService.login时:

expect(usersService.login).toHaveBeenCalled();
我得到一个错误,因为observable没有完成,登录还没有被调用


我应该如何确保,我检查我的间谍后,observable已经完成

我不知道您如何在组件上配置服务,但当我覆盖从
TestComponentBuilder
创建的组件的提供程序时,它对我有效

我们来取样吧。我有一个返回字符串列表的服务:

import {Observable} from 'rxjs/Rx';

export class MyService {
  getDogs() {
    return Observable.of([ 's1', 's2', ... ]);
  }
}
组件使用此服务在单击按钮时异步显示列表:

@Component({
  selector: 'my-list',
  providers: [MyService],
  template: `
    <ul><li *ngFor="#item of items">{{ item }}</li></ul>
    <div id="test" (click)="test()">Test</div>
  `
})
export class MyList implements OnInit {
  items:Array<string>;
  service:MyService;

  constructor(private service:MyService) {
  }

  test() {
    this.service.getDogs().subscribe(
      (dogs) => {
        this.items = dogs;
      });
  }
}
编辑

由于异步触发事件,可以考虑使用<代码> FAKAASYNC 。后者允许您完全控制何时处理异步处理,并将异步事务转换为同步事务

您可以将测试处理包装到

fakeAsync((): void => {
  var clickButton = document.getElementById('test');
  clickButton.dispatchEvent(new Event("click"));

  expect(service.getDogs).toHaveBeenCalled();
});
有关更多详细信息,您可以查看以下问题:


谢谢您的回答。我也是这样做的,但在我的例子中,TohaveBeenCall是在组件调用服务方法之前被检查的。我不确定是否理解;-)组件以同步方式调用服务,服务方法执行异步操作并返回一个可观察的。是吗?是的,没错,但据我所知,dispatchEvent是异步的,因此在异步模式下调用test()函数,在调用getDogs之前可能会检查expect。如何执行测试?用因果报应?如果你想等待可观测的接收数据,你可以考虑使用<代码> FAKAASYNC < /代码>。后者允许您完全控制何时处理异步处理,并将异步内容转换为同步内容;-)您应该对这个问题感兴趣:。
let service:MyService = new MyService();

beforeEach(() => {
    spyOn(service, 'getDogs').and.returnValue(Observable.of(
        ['dog1', 'dog2', 'dog3']));

});

it('should test get dogs', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
    return tcb.overrideProviders(MyList, [provide(MyService, { useValue: service })])
              .createAsync(MyList).then((componentFixture: ComponentFixture) => {
        const element = componentFixture.nativeElement;
        componentFixture.detectChanges();

        var clickButton = document.getElementById('test');
        clickButton.dispatchEvent(new Event("click"));

        expect(service.getDogs).toHaveBeenCalled();
    });
}));
fakeAsync((): void => {
  var clickButton = document.getElementById('test');
  clickButton.dispatchEvent(new Event("click"));

  expect(service.getDogs).toHaveBeenCalled();
});