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

install({ toFake: ["setImmediate"] }) fails when setImmediate is not available in context (such as browser environment) #490

Closed
hi-ogawa opened this issue Jan 23, 2024 · 5 comments · Fixed by #491

Comments

@hi-ogawa
Copy link

hi-ogawa commented Jan 23, 2024

What did you expect to happen?

No error. Preferably allow faking setImmediate even when it's not available in the context, which would align with current behavior with requestIdleCallback, requestAnimationFrame etc... (see repro-other.mjs in reproduction).

What actually happens

Error: Cannot set properties of undefined (setting 'hadOwnProperty')

How to reproduce

import { withGlobal } from '@sinonjs/fake-timers';

function main() {
  const global = { Date, setTimeout, clearTimeout };
  const timers = withGlobal(global);

  // error when install
  // > Error: Cannot set properties of undefined (setting 'hadOwnProperty')
  const clock = timers.install({ toFake: ['setImmediate'] });
}

main();

extra context of the issue

First of all, thanks for making this portable library for timer mocking!
I found some inconsistency of @sinonjs/fake-timers while investigating an issue on Vitest vitest-dev/vitest#5027 (comment). There is a workaround on Vitest side so it's not critical, but I thought it's worth reporting an issue.

This is likely a same issue as #277 but I think the issue still persists since the verification #277 (comment) seems to be done on NodeJS where setImmediate is globally available but this is not the case on browsers.

I'm not sure what's desired behavior, but there seems slight inconsistency whether @sinonjs/fake-timers fakes what's not globally available. From what I tried so far, { toFake: ["requestIdleCallback"] } works even when it's not globally available (for example, this is browser-only and not available on NodeJS). On the other hand, { toFake: ["setImmediate"] } throws an error on browser.

@hi-ogawa hi-ogawa changed the title install({ toFake: ["setImmediate"] }) fails when it's not available in context install({ toFake: ["setImmediate"] }) fails when setImmediate not available in context (such as browser environment) Jan 23, 2024
@hi-ogawa hi-ogawa changed the title install({ toFake: ["setImmediate"] }) fails when setImmediate not available in context (such as browser environment) install({ toFake: ["setImmediate"] }) fails when setImmediate is not available in context (such as browser environment) Jan 23, 2024
@fatso83
Copy link
Contributor

fatso83 commented Jan 23, 2024

Good call. Whatever we do, it should be consistent. I usually like to be strict (as in throwing an error, possibly overridable with a flag), but we could also do the reverse.

@SimenB
Copy link
Member

SimenB commented Jan 23, 2024

Failing with an explicit error in either case seems reasonable, but that might be considered a breaking change?

@hi-ogawa
Copy link
Author

hi-ogawa commented Jan 23, 2024

Thanks for the follow up.

Failing with an explicit error in either case seems reasonable, but that might be considered a breaking change?

I think stop faking/providing requestIdleCallback when it's not globally available (such as plain NodeJS) would be a breaking change since that's essentially what happened with Vitest vitest-dev/vitest#5027 (comment)

I haven't checked properly yet, but it seems jsdom/happy-dom doesn't provide requestIdleCallback global either while they do provide requestAnimationFrame etc... If they were providing requestIdleCallback, then I could've suggested users to switch to jsdom/happy-dom, so In some sense, this could be considered jsdom/happy-dom side issue as well. I'd love to hear what you think.
(EDIT: I mentioned jsdom here but I guess this is a different matter. I just thought worth mentioning since inconsistency visible to users at the test framework level can potentially depend on jsdom usage.)

@fatso83
Copy link
Contributor

fatso83 commented Jan 23, 2024

Failing with an explicit error in either case seems reasonable, but that might be considered a breaking change?

Absolutely, but I would also add a flag to silence those errors to have an easy fallback to the previous behaviour. That way Jest could consume fake-timers@12 by passing ignoreMissingTimers: true (just a suggestion) by default.

@fatso83
Copy link
Contributor

fatso83 commented Feb 10, 2024

Added the breaking change in #491 with a flag to ignore missing. That should make the behaviour consistent going forwards and maybe make introducing #323 simpler. Took a lot more effort to get the testcases working than expected, but at least it is now working.

Have a look, otherwise I'll just merge in a few days.

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

Successfully merging a pull request may close this issue.

3 participants