Ложная задержка () RxJS с Jest - PullRequest
6 голосов
/ 08 апреля 2019

Есть ли простой способ смоделировать delay() метод RxJS в наблюдаемом с фальшивым временем, например?

У меня есть этот метод:

register(user) {
  return this._checkLog(user).delay(500).flatMap( ... )
}

Когда я удаляю метод delay(), мои тесты из _register () все успешно выполняются.

Ответы [ 3 ]

2 голосов
/ 14 апреля 2019

RxJS v6

Для кода RxJS v6:

code.js

import { of } from 'rxjs';
import { delay } from 'rxjs/operators';

export const example = of('hello').pipe(
  delay(1000)
);

... вы можете использовать sinon фальшивые таймеры , например:

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 таймеры высмеивают не работают, не знаю почему)


... или вы можете высмеивать 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

Для кода 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!
  });
});
0 голосов
/ 06 июня 2019

, чтобы завершить решение brian-live-outdoor для RxJS 6, вы также можете высмеивать реальное поведение delay (), используя delayWhen и таймер, который работает с jest:

 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();
  });
0 голосов
/ 15 апреля 2019

Мы используем Scheduler s из Rxjs.

Класс выглядит примерно так:

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.Какой планировщик вы хотите или должны использовать в компоненте, должен соответствовать вашему сценарию использования, в лучшем случае посмотрите документацию и выясните, что вам больше подходит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...