javascript - Jasmine:用事件测试可观察量

标签 javascript testing typescript jasmine angular

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

doLogin() {
    this.usersService.login(this.model)
        .subscribe((data) => {
            console.log("In observable: " + data.isSuccess);
            if (!data.isSuccess) {
                this.alerts.push({});
            }
        });
}

在测试中,我在服务函数上添加了一个 spy ,该函数返回可观察的,以便该组件可以对其进行工作:

 usersService.login.and.returnValue(Observable.of(
    <LoginResponse>{
        isSuccess: true
    }));

当一切准备就绪后,我在提交按钮上调度一个事件,该事件触发组件中的 doLogin 函数:

submitButton.dispatchEvent(new Event("click"));
fixture.detectChanges();

它工作正常。不幸的是,当我检查测试中是否调用了 usersService.login 时:

expect(usersService.login).toHaveBeenCalled();

我收到错误,因为可观察尚未完成并且尚未调用登录。

我应该如何确保在 observable 完成后检查我的 spy ?

最佳答案

我不知道如何在组件上配置服务,但当我重写从 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;
      });
  }
}

我想测试当我点击“Test”按钮时,调用组件的test方法并间接调用服务的getDogs方法.

为此,我创建了一个测试,直接实例化服务并使用 TestComponentBuilder 加载组件。在这种情况下,我需要在调用 createAsync 之前调用它的 overrideProviders 方法。这样,您将能够提供 spy 服务以收到调用通知。这是一个示例:

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。后者允许您完全控制异步处理的处理时间,并将异步处理转变为同步处理。

您可以将测试处理包装到

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

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

有关更多详细信息,您可以查看以下问题:

关于javascript - Jasmine:用事件测试可观察量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36422160/

相关文章:

javascript - jQuery 最佳实践 : hide/doSomething/show sequence

javascript - 使用 jquery 获取动态创建的元素的内容

javascript - 使用javascript在客户端机器上保存文本文件

ruby-on-rails - rails : How to modify tests for a nested resource?

testing - 使用 boost.test 进行复杂的检查方法

javascript - 在 Mat-Select : Angular 6 中滚动到 Mat-0options 末尾时触发事件

javascript - Angular 垫输入

javascript - 如何转义像 "\\r\\n "这样的清理字符串

unit-testing - 是否可以将用户输入保存在变量中以使用 intellij (pycharm) 进行连续测试

node.js - TypeScript: Node 11 的 "right" `target` 是什么?