Angular 2 Observable测试错误:无法在异步区域测试中使用setInterval

时间:2016-10-25 14:20:45

标签: unit-testing asynchronous angular typescript jasmine

我正在尝试测试一个使用服务进行异步http调用的组件。该服务返回一个Observable,组件订阅了它。

服务代码段:

getRecentMachineTemperatures(_machine_Id): Observable<IDeviceReadings[]> {

    return this.http.get(TemperatureService.URL + _machine_Id)
      .map(response => { return response.json(); })
      .map((records: Array<any>) => {
        let result = new Array<IDeviceReadings>();
        if (records) {
          records.forEach((record) => {
            let device = new IDeviceReadings();
            device.device_id = record.device_id;

            if (record.d) {
              record.d.forEach((t) => {
                let temperature = new ITemperature();
                temperature.timestamp = t.timestamp;
                temperature.value = t.temperature;

                device.temperatures.push(temperature);
              });
            }

            result.push(device);
          });
        }
        return result;
      });
  }

组件代码段:

  ngOnInit() {
    this.getRecentTemperatures();
  }

  getRecentTemperatures() {
    this.temperatureService.getRecentMachineTemperatures(this.machine_id)
      .subscribe(
        res => {
          let device1 = res[0];
          this.deviceId = device1.device_id;
          this.initTemperatures(device1.temperatures);
          this.updateChart();
        },
        error => console.log(error));
  }

我的测试设置依赖关系,间谍服务'getRecentMachineTemperatures'并设置i返回一些存根数据。我一直在谷歌搜索测试这个的方法,从而导致3个不同的测试,试图测试同样的事情。每个人都给我一个不同的错误。

temperature.component.spec.ts:

let machine_id = 1;
let comp:                 TemperatureComponent;
let fixture:              ComponentFixture<TemperatureComponent>;
let de:                   DebugElement;
let el:                   HTMLElement;
let temperatureService:   TemperatureService;
let stubDevices:          IDeviceReadings[];
let stubTemperatures:     ITemperature[];
let spyRecentTemps:       Function;

describe('Component: Temperature', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [TemperatureComponent],
      imports: [ ChartsModule ],
      providers: [
        MockBackend,
        BaseRequestOptions,
        { provide: Http,
          useFactory: (backend, defaultOptions) => {
            return new Http(backend, defaultOptions);
          },
          deps: [MockBackend, BaseRequestOptions]},
        TemperatureService
      ]
    });

    stubDevices = new Array<IDeviceReadings>();

    let stubDevice = new IDeviceReadings();
    stubDevice.device_id = 'stub device';
    stubDevice.temperatures = new Array<ITemperature>();

    let stubTemp = new ITemperature();
    stubTemp.timestamp = new Date().getTime();
    stubTemp.value = 10;

    stubDevice.temperatures.push(stubTemp);
    stubDevices.push(stubDevice);

    stubTemperatures = new Array<ITemperature>();

    let stubTemp2 = new ITemperature();
    stubTemp.timestamp = new Date().getTime() + 1;
    stubTemp.value = 11;

    stubTemperatures.push(stubTemp2);

    fixture = TestBed.createComponent(TemperatureComponent);
    comp = fixture.componentInstance;

    temperatureService = fixture.debugElement.injector.get(TemperatureService);

    spyRecentTemps = spyOn(temperatureService, 'getRecentMachineTemperatures')
      .and.returnValue(Observable.of(stubDevices).delay(1));

    //  get the "temperature-component" element by CSS selector (e.g., by class name)
    de = fixture.debugElement.query(By.css('.temperature-component'));
    el = de.nativeElement;
  });

  it('should show device readings after getRecentTemperatures subscribe (fakeAsync)', fakeAsync(() => {
    fixture.detectChanges();
    expect(spyRecentTemps.calls.any()).toBe(true, 'getRecentTemperatures called');

    tick(1000);
    fixture.detectChanges();
    expect(el.textContent).toContain(stubDevices[0].temperatures[0].timestamp);
    expect(el.textContent).toContain(stubDevices[0].temperatures[0].value);
  }));

  it('should show device readings after getRecentTemperatures subscribe (async)', async(() => {
      fixture.detectChanges();
      expect(spyRecentTemps.calls.any()).toBe(true, 'getRecentTemperatures called');

      fixture.whenStable().then(() => {
        fixture.detectChanges();
        expect(el.textContent).toContain(stubDevices[0].temperatures[0].timestamp);
        expect(el.textContent).toContain(stubDevices[0].temperatures[0].value);
      });
  }));

  it('should show device readings after getRecentTemperatures subscribe (async) (done)', (done) => {
    async(() => {
      fixture.detectChanges();
      expect(spyRecentTemps.calls.any()).toBe(true, 'getRecentTemperatures called');

      fixture.whenStable().then(() => {
        fixture.detectChanges();
        expect(el.textContent).toContain(stubDevices[0].temperatures[0].timestamp);
        expect(el.textContent).toContain(stubDevices[0].temperatures[0].value);
      }).then(done);
    });
  });
});

fakeAsync失败并显示:'错误:1个计时器仍在队列中。'

async失败并显示:'错误:无法在异步区域测试中使用setInterval。'

async(done)失败并显示:'错误:超时 - 在jasmine.DEFAULT_TIMEOUT_INTERVAL指定的超时时间内未调用异步回调。'

如何使用异步服务依赖项测试组件?

根据我的理解,它可能是使用Date()的Rx库中的AsyncScheduler。现在而不是伪造的时间(https://github.com/angular/angular/issues/10127)。如果是这样,这是固定的吗?或者有人找到了解决方法?

我正在使用angular-cli:1.0.0-beta.16。节点:4.4.2。 npm:3.10.6。 webpack 2.1.0-beta.22。

1 个答案:

答案 0 :(得分:2)

我有..

import 'rxjs/add/operator/timeout';

return this.http[method](url, emit, this.options)
    .timeout(Config.http.timeout, new Error('timeout'))

导致此错误的原因。我相信在引擎盖下RXJS .timeout正在调用setInterval。

我通过切换来解决这个问题......

it('blah', async(() => {     

it('blah', (done) => {