是否有一种简单的方法来模拟RxJS的delay()
方法,例如在虚假的时间内进行观察?
我有这种方法:
register(user) {
return this._checkLog(user).delay(500).flatMap( ... )
}
当我删除delay()
方法时,我从_register()进行的测试全部成功。
答案 0 :(得分:2)
对于RxJS v6这样的代码:
code.js
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
export const example = of('hello').pipe(
delay(1000)
);
...您可以像这样使用sinon
fake timers:
import * as sinon from 'sinon';
import { example } from './code';
describe('delay', () => {
let clock;
beforeEach(() => { clock = sinon.useFakeTimers(); });
afterEach(() => { clock.restore(); });
it('should delay one second', () => {
const spy = jest.fn();
example.subscribe(spy);
expect(spy).not.toHaveBeenCalled(); // Success!
clock.tick(1000);
expect(spy).toHaveBeenCalledWith('hello'); // Success!
});
});
(请注意,在撰写Jest
timer mocks时不起作用,不确定为什么)
...或者您可以嘲笑delay
来执行以下操作:
import { delay } from 'rxjs/operators';
import { example } from './code';
jest.mock('rxjs/operators', () => {
const operators = jest.requireActual('rxjs/operators');
operators.delay = jest.fn(() => (s) => s); // <= mock delay
return operators;
});
describe('delay', () => {
it('should delay one second', () => {
const spy = jest.fn();
example.subscribe(spy);
expect(delay).toHaveBeenCalledWith(1000); // Success!
expect(spy).toHaveBeenCalledWith('hello'); // Success!
});
});
对于RxJS v5这样的代码:
code.js
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/delay';
export const example = Observable.of('hello').delay(1000);
...您可以嘲笑delay
来执行以下操作:
import { Observable } from 'rxjs/Observable';
import { example } from './code';
jest.mock('rxjs/add/operator/delay', () => {
const Observable = require('rxjs/Observable').Observable;
Observable.prototype.delay = jest.fn(function () { return this; }); // <= mock delay
});
describe('delay', () => {
it('should delay one second', () => {
const spy = jest.fn();
example.subscribe(spy);
expect(Observable.prototype.delay).toHaveBeenCalledWith(1000); // Success!
expect(spy).toHaveBeenCalledWith('hello'); // Success!
});
});
答案 1 :(得分:1)
从 6.2.1 版本开始,RxJS 支持 Jest 的假时间,所以你可以简单地写
jest.useFakeTimers('modern');
test('...', () => {
// ...code that subscribes to your observable.
jest.runAllTimers();
// ...code that makes assertions.
});
此外,我发布了一个 library,它使编写此类测试更容易,这是一个示例(log
将日志记录添加到 observable,getMessages
检索已记录的消息):>
import { getMessages, log } from '1log';
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
test('delay', () => {
of(42).pipe(delay(500), log).subscribe();
jest.runAllTimers();
expect(getMessages()).toMatchInlineSnapshot(`
[create 1] +0ms [Observable]
[create 1] [subscribe 1] +0ms [Subscriber]
[create 1] [subscribe 1] [next] +500ms 42
[create 1] [subscribe 1] [complete] +0ms
· [create 1] [subscribe 1] [unsubscribe] +0ms
`);
});
答案 2 :(得分:0)
我们正在使用Rxjs中的Scheduler
s。
类看起来像这样:
import { Observable, Scheduler, Subject, asapScheduler } from 'rxjs';
// ...
constructor(
@Optional() private readonly _scheduler: Scheduler
) {
if (isNullOrUndefined(_scheduler)) {
this._scheduler = asapScheduler;
}
}
// ...
this._someObservable.pipe(delay(1, this._scheduler));
然后,在规格文件中的TestModuleMetadata
中提供模拟:
{
declarations: [YourComponent],
imports: [],
providers: [
{ provide: Scheduler, useValue: new VirtualTimeScheduler() },
],
};
现在,您需要做的就是在beforeEach
块中分配调度程序,并在希望“跳过”延迟时刷新它:
let schedulerMock = Testbed.get(Scheduler);
// ...
it('should emit true', () => {
let result: boolean = null;
comp.someObservable.subscribe(next => (result = next));
schedulerMock.flush();
expect(result).toBe(true);
});
这也适用于其他时间相关的运算符,例如bufferTime
。
您要使用或需要在组件中使用哪个调度程序应取决于您的用例,在最佳情况下,请查阅文档并找出最适合您的方案。
答案 3 :(得分:0)
要完成RxJS 6的brian-live-outdoor解决方案,您还可以使用delayWhen和与jest配合使用的计时器来模拟delay()的实际行为:
jest.mock("rxjs/operators", () => {
const operators = jest.requireActual("rxjs/operators");
const observables = jest.requireActual("rxjs");
operators.delay = jest.fn(delay => s =>
s.pipe(operators.delayWhen(() => observables.timer(delay)))
);
return operators;
});
,您可以将此模拟放到node_modules文件夹旁边:
.
├── __mocks__
│ └── rxjs
│ └── operators.js
└── node_modules
// operators.js
const operators = require("rxjs/operators");
const observables = require("rxjs");
operators.delay = jest.fn(delay => s =>
s.pipe(operators.delayWhen(() => observables.timer(delay)))
);
module.exports = operators;
一个以前无法使用且无法与该模拟一起使用的测试示例:
it("some test with delay()", (done: DoneFn) => {
let check = false;
jest.useFakeTimers();
of(true)
.pipe(delay(1000))
.subscribe(() => (check = true));
setTimeout(() => {
expect(check).toBe(true);
done();
}, 2000);
jest.runTimersToTime(999);
expect(check).toBe(false);
jest.runAllTimers();
});