[英]Test Observable with fakeAsync, delay and tick using Jasmine
I have a pipe that helps return the state of an observable.我有一个 pipe 可以帮助返回一个 observable 的 state。
import {Pipe, PipeTransform} from '@angular/core';
import {Observable, of} from 'rxjs';
import {catchError, map, startWith} from 'rxjs/operators';
/** Specifies the status of an Observable. */
export interface ObservableStatus<T> {
loading?: boolean;
value?: T;
error?: boolean;
}
/** Returns the status {@code ObservableStatus} of a given Observable. */
@Pipe({name: 'getObserverStatus'})
export class ObservableStatusPipe implements PipeTransform {
transform<T = Item>(observer: Observable<T>):
Observable<ObservableStatus<T>> {
return observer.pipe(
map((value: T) => {
return {
loading: false,
error: false,
value,
};
}),
startWith({loading: true}),
catchError(error => of({loading: false, error: true})));
}
}
I want to write unit tests for this functionality using Jasmine. I tried using fakeAsync, delay, tick, flush, discardPeriodicTasks
but it doesn't seem to work.我想使用 Jasmine 为该功能编写单元测试。我尝试使用fakeAsync, delay, tick, flush, discardPeriodicTasks
但它似乎不起作用。
describe('loading test', () => {
const loadingPipe = new ObservableStatusPipe();
it('returns state of an observable', fakeAsync(() => {
const input: Observable<Item> = of({name: 'Item'}).pipe(delay(1000));
const result: Observable<ObservableStatus<Item>> = loadingPipe.transform(input);
result.subscribe(val => {
expect(val.loading).toEqual(true);
expect(val.value).toBeUndefined();
});
tick(2000);
result.subscribe(val => {
expect(val.loading).toEqual(false);
expect(val.value!.name).toEqual('Item');
});
}));
});
The above test case fails with following failures:上述测试用例失败并出现以下故障:
Error: Expected true to equal false. (at expect(val.loading).toEqual(false))
Error: 1 periodic timer(s) still in the queue.
describe('loading test', () => {
const loadingPipe = new ObservableStatusPipe();
it('returns state of an observable', fakeAsync(() => {
const input: Observable<Item> = of({name: 'Item'}).pipe(delay(1000));
const result: Observable<ObservableStatus<Item>> = loadingPipe.transform(input);
result.subscribe(val => {
expect(val.loading).toEqual(true);
expect(val.value).toBeUndefined();
});
tick(2000);
result.subscribe(val => {
expect(val.loading).toEqual(false);
expect(val.value!.name).toEqual('Item');
});
flush(); // <----- here.
}));
});
This is helping to resolve Error: 1 periodic timer(s) still in the queue.
这有助于解决Error: 1 periodic timer(s) still in the queue.
issue.问题。 However the test case still fails with:但是测试用例仍然失败:
Error: Expected true to equal false.
TypeError: Cannot read properties of undefined (reading 'name')
Does all this mean the tick
is somehow not simulating time on input
observable?所有这一切是否意味着tick
以某种方式不模拟可观察到的input
时间?
input
observable directly:我直接在input
observable 上测试了相同的模拟:describe('loading test', () => {
const loadingPipe = new ObservableStatusPipe();
it('returns state of an observable', fakeAsync(() => {
const input: Observable<Item> = of({name: 'Item'}).pipe(delay(1000));
input.subscribe(val => {
expect(val.name).toBeUndefined();
});
tick(2000);
input.subscribe(val => {
expect(val.name).toEqual('Item');
});
discardPeriodicTasks(); <--- Using flush() here is causing 'Error: 2 periodic timer(s) still in the queue' error.
}));
});
The above test case is passing.以上测试用例通过。 But I am still confused why flush() is not working here.但我仍然很困惑为什么 flush() 在这里不起作用。
describe('loading test', () => {
const loadingPipe = new ObservableStatusPipe();
it('returns state of an observable', fakeAsync(() => {
const input: Observable<Item> = of({name: 'Item'}).pipe(delay(1000));
const result: Observable<ObservableStatus<Item>> = loadingPipe.transform(input);
result.subscribe(val => {
expect(val.loading).toEqual(true);
expect(val.value).toBeUndefined();
});
tick(2000);
result.subscribe(val => {
expect(val.loading).toEqual(false);
expect(val.value!.name).toEqual('Item');
});
discardPeriodicTasks();
}));
});
This still fails with the same errors:这仍然失败并出现相同的错误:
Error: Expected true to equal false. (at expect(val.loading).toEqual(false))
Error: 1 periodic timer(s) still in the queue.
Can someone explain what is happening here, and how to solve this, please?有人可以解释这里发生了什么,以及如何解决这个问题吗?
Btw, I do not want to use debounceTime
, setTimeOut
to solve this problem.顺便说一句,我不想使用debounceTime
, setTimeOut
来解决这个问题。 Because they do not seem to simulate time, instead actually waits and delays time ie using debounceTime(1000) will actually wait for 1 sec.因为它们似乎没有模拟时间,而是实际等待和延迟时间,即使用 debounceTime(1000) 实际上会等待 1 秒。 I do not want that in my case (I want to simulate time).我不想这样(我想模拟时间)。
delay
operator while subscribing the observable is working (without using tick
).在订阅可观察对象时使用delay
运算符是有效的(不使用tick
)。describe('loading test', () => {
const loadingPipe = new ObservableStatusPipe();
it('returns state of an observable', fakeAsync(() => {
const input: Observable<Item> = of({name: 'Item'}).pipe(delay(1000));
const result: Observable<ObservableStatus<Item>> = loadingPipe.transform(input);
result.subscribe(val => {
expect(val.loading).toEqual(true);
expect(val.value).toBeUndefined();
});
result.pipe(delay(2000)).subscribe(val => {
expect(val.loading).toEqual(false);
expect(val.value!.name).toEqual('Item');
});
discardPeriodicTasks();
}));
});
Is this actually delaying/waiting for 1000 or 2000ms, or does using fakeAsync somehow let delay to simulate the time?这实际上是延迟/等待 1000 或 2000 毫秒,还是使用 fakeAsync 以某种方式让延迟模拟时间?
Thanks!谢谢!
I think your way 1 is good but you may be facing a situation of late subscribers and multiple subscriptions.我认为你的方式 1 很好,但你可能面临延迟订阅和多个订阅的情况。 Try this:试试这个:
// Take 2 emissions
result.pipe(take(2)).subscribe(val => {
if (val.loading) {
console.log('False case');
expect(val.loading).toEqual(true);
expect(val.value).toBeUndefined();
} else {
console.log('True case');
expect(val.loading).toEqual(false);
expect(val.value!.name).toEqual('Item');
}
});
// Move time in a fake way. The above observable stream should hopefully emit
// twice and therefore there is a take(2).
// Make sure you see both console.logs to ensure both paths were asserted.
tick(2000);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.