-
-
Notifications
You must be signed in to change notification settings - Fork 769
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can you add usePromisePolyfill() or an option to useFakeTimers's config? #1529
Comments
Have you checked out |
I am not sure i am doing this the right way but here is what i get. What i understand usingPromise() only works on stub methods like resolves and rejects. This example works for my case but i don't get how we can use this in complex scenarios. The problem is, when we call clock.tick() it does not wait for promises to resolve because native promise does not use timers. Should we stub everything that uses promises instead of replacing global Promise temporarily? I just started using sinon and sorry if i am asking something silly. DirectoryWatcher.tsimport * as path from 'path';
import { EventEmitter } from 'events';
import { pathExists } from 'fs-extra';
export class DirectoryWatcher extends EventEmitter {
private timerId: NodeJS.Timer;
constructor(private interval: number = 2000) {
super();
}
public start() {
if (this.timerId) return;
this.set();
}
public stop() {
if (this.timerId) {
clearTimeout(this.timerId);
}
}
private watchAction() {
pathExists('').then(exists => {
this.emit('change', exists);
}, error => {
this.emit('error', error);
}).then(() => {
this.set();
});
}
private set() {
this.timerId = setTimeout(() => this.watchAction(), this.interval);
}
} DirectoryWatcher.test.tsimport { expect, use as chaiUse } from 'chai';
import * as sinon from 'sinon';
import * as sinonChai from 'sinon-chai';
import * as fs from 'fs-extra';
chaiUse(sinonChai);
const promisePolyfill = require('promise-polyfill');
import { DirectoryWatcher } from '../src/DirectoryWatcher';
suite('With usingPromise()', function () {
let watcher: DirectoryWatcher;
let clock: sinon.SinonFakeTimers;
let callback: sinon.SinonSpy;
let pathExistsStub: sinon.SinonStub;
let watcherStub: sinon.SinonStub;
setup(() => {
clock = sinon.useFakeTimers(10000);
watcher = new DirectoryWatcher(2000);
callback = sinon.spy();
watcher.on('change', callback);
});
teardown(() => {
watcher.stop();
watcher.removeAllListeners('change');
clock.restore();
pathExistsStub.restore();
});
test('Should find directory', () => {
stubPathExists(true);
watcher.start();
clock.tick(6500);
expect(callback).to.be.calledThrice;
expect(callback).to.be.calledWith(true);
});
test('Should not find directory', () => {
stubPathExists(false);
watcher.start();
clock.tick(6500);
expect(callback).to.be.calledThrice;
expect(callback).to.be.calledWith(false);
});
function stubPathExists(result: boolean) {
if (pathExistsStub) {
pathExistsStub.restore();
}
pathExistsStub = sinon.stub(fs, 'pathExists').usingPromise(promisePolyfill).resolves(result);
}
}); |
Thanks for elaborating. Unfortunately you just opened a can of worms 😁 The core problem is how to deal with asynchronous bits in the synchronous world of Lolex (which is responsible for Sinon's fake timers). Progress on how to deal with promises has stalled on the Lolex project, so we have no official path going forward. For an interesting discussion see sinonjs/fake-timers#105. For the moment you can hack around the issue. Save a reference to the original setTimeout and call that in between timer ticks to resolve promises. |
As @ropez stated in his issue 738, replacing global Promise with polyfill solves the issue with native promises when using fake timers. But we should be able to restore it after tests are finished.
This is how i solve the problem.
How about something like this?
The text was updated successfully, but these errors were encountered: