Skip to content
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

Increase compatiblity with faking time in test tools #15

Merged

Conversation

mroderick
Copy link

By caching reference to the global setImmediate and setTimeout we can ensure
that promise-polyfill still works as excpected when using fake timers in unit test scenarios.

See

@taylorhakes
Copy link
Owner

I feel like sinon.useFakeTimers should affect this library. Why do you feel it shouldn't?

I imagine there are people using fakeTimers with this library currently.

@mroderick
Copy link
Author

I feel like sinon.useFakeTimers should affect this library. Why do you feel it shouldn't?

I ran into issues where my time dependent tests that use sinon.useFakeTimers() would pass in Firefox (native promises), but fail in PhantomJS (promise-polyfill).
This PR makes the tests behave the same in both browsers.

Here's my understanding of how promise-polyfill is using setTimeout:

We define an asap function, that is used for ensuring that work can be put on a new call stack, so to emulate the asynchronous nature of promises. The important part of this is not to be able to accurately control time, but only to ensure that work is done on a new call stack.

If that is correct, then this PR ensures that promise is kept (accidental pun) even when the global� setTimeout is being manipulated.

I imagine there are people using fakeTimers with this library currently.

I would imagine so as well. Perhaps best bump the major version, if this PR is merged.

@codazzo
Copy link

codazzo commented Jan 7, 2016

Hi @taylorhakes, thanks for your prompt reply! I ran into the same issue as (well, together with) @mroderick. I tried to exemplify the reasoning behind the shadowing in this jsbin:

http://jsbin.com/metoma/edit?html,js,output

I pasted a near-verbatim version of Promise.js (as of the master branch) in the HTML tab of the bin. The only difference is I actually force the polyfill over native implementations so the behaviour could be exhibited in browsers that implement Promise (see the bottom of the script).
If you comment out the lines that shadow (or "cache") setTimeout and setInterval at the top of the file, the tests time out. This happens because the tests return a promise (https://mochajs.org/#working-with-promises) but since the Promise constructor relies on setTimeout (which, if you comment out the shadowing lines, is stubbed), the runner is unable to wait on the promise and the tests time out.

I hope that was clear enough. We had to make the change in this PR in order for our tests (somewhat similar to the test in the bin) to pass. Do you think it makes sense?

@taylorhakes
Copy link
Owner

Thanks @mroderick and @codazzo for the detailed explanations. I completely understand your reasoning now.

I plan to move forward with this merge, but I would like to let this sit open for a couple more days. I want to make sure I am not forgetting something. If others have any objections, it will give them time to speak up.

I will plan to make this change for v3.

@taylorhakes
Copy link
Owner

This change can be implemented in one line I believe. setImmediate is already stored locally on the asap line.

// Store setTimeout to not be affected by mocking
var setTimeout = setTimeout;

Do you mind making that change? Also, please format it with tabs instead of spaces.

@mroderick mroderick mentioned this pull request Jan 8, 2016
@mroderick
Copy link
Author

Do you mind making that change?

Not at all. I've pushed changes and the build is green :)

Also, please format it with tabs instead of spaces.

My apologies, I am so used to having an .editorconfig ... I have opened #16 to add one.

@taylorhakes
Copy link
Owner

Do we need to reference root.setTimeout? Can't we just write

var setTimeout = setTimeout;

We then also don't need the change at the bottom with global. The global line at the bottom won't work in browsers. I should probably make the build run in browsers to catch those types of errors.

Please add the a comment above the setTimeout line. Something like

// Store setTimeout to not be affected by mocking

to make sure we remember why it is being done.

By caching reference to the global setImmediate and setTimeout we can ensure
that promise-polyfill still works as excpected when sinon.useFakeTimers()
replaces them with fake versions.
@mroderick
Copy link
Author

Updated as requested

taylorhakes added a commit that referenced this pull request Jan 8, 2016
Increase compatiblity with faking time in test tools
@taylorhakes taylorhakes merged commit 7ddc003 into taylorhakes:master Jan 8, 2016
@taylorhakes
Copy link
Owner

Perfect. I will release a new version to NPM tonight

@mroderick
Copy link
Author

Thanks!

@mroderick mroderick deleted the increase-sinon-compatibility branch January 8, 2016 17:27
@codazzo
Copy link

codazzo commented Jan 9, 2016

Thanks! 🎉

@taylorhakes
Copy link
Owner

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants