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

Interpretter clock.setTimeout method does not work in Firefox WebExtension content scripts by default #1703

Closed
blimmer opened this issue Dec 7, 2020 · 7 comments · Fixed by #1704
Labels

Comments

@blimmer
Copy link
Contributor

blimmer commented Dec 7, 2020

Description

When an XState machine with delayed events/transitions is used in a Firefox WebExtension content script, the default implementation of clock.setTimeout and clock.clearTimeout throws this exception:

TypeError: 'setTimeout' called on an object that does not implement interface Window.

Expected Result

I expected the machine, as defined, to work without throwing an exception.

Actual Result

An exception is thrown, and the state machine does not work properly.

Reproduction

Because this happens in a Firefox WebExtension, I couldn't use any of the recommended reproduction templates. Instead, I created a sample repository to show the issue: https://github.com/blimmer/xstate-webext-setTimeout-issue. There is information in the Quick Start section of the README that explains how to run the example.

Additional context

This issue seems to be caused by the default implementation of setTimeout/clearTimeout defined here: https://github.com/davidkpiano/xstate/blob/844c2c30d6160763ab164dc0592e33a942746361/packages/core/src/interpreter.ts#L125-L132

I believe the issue is with thisArg being null. I locally changed the default implementation to look like this (note the global thisArg) and the state machine started working with the default implementation.

clock: {
  setTimeout: (fn, ms) => {
    return global.setTimeout.call(global, fn, ms);
  },
  clearTimeout: (id) => {
    return global.clearTimeout.call(global, id);
  }
},

I was looking at the history and noticed that @davidkpiano change the default clock behavior in this commit to use the .call(null, ...args) pattern. This makes sense since you want setTimeout bound to the global instance passed in, but I think Firefox is doing some additional checks on the thisArg which causes this error.

@davidkpiano
Copy link
Member

@blimmer Thanks for the investigation! I'll fix this soon.

@davidkpiano davidkpiano added the bug label Dec 7, 2020
@blimmer
Copy link
Contributor Author

blimmer commented Dec 7, 2020

No problem at all! Thank you so much for the quick response, I really appreciate it.

Does the global thisArg make sense as a fix? If so, I'd be happy to open a PR.

@davidkpiano
Copy link
Member

No problem at all! Thank you so much for the quick response, I really appreciate it.

Does the global thisArg make sense as a fix? If so, I'd be happy to open a PR.

Yes it does; I'd appreciate a PR!

For tests, this might be hard to test since it's a Firefox-specific thing, so as long as the existing tests pass, that's sufficient.

@Andarist
Copy link
Member

Andarist commented Dec 7, 2020

It probably should be enough to just remove global. from those calls. I cant name any JS env in which those (setTimeout & clearTimeout) wouldnt be globally available.

@davidkpiano
Copy link
Member

It probably should be enough to just remove global. from those calls. I cant name any JS env in which those (setTimeout & clearTimeout) wouldnt be globally available.

I can't remember why, but there was a reason I used global, whereas setTimeout/clearTimeout wouldn't work.

blimmer added a commit to blimmer/xstate that referenced this issue Dec 7, 2020
blimmer added a commit to blimmer/xstate that referenced this issue Dec 7, 2020
@blimmer
Copy link
Contributor Author

blimmer commented Dec 7, 2020

Yeah, I was wondering what the background was on why the global call was originally added. The commit message made it seem like there was something you ran into that required it.

66c8cf2

Cleanup, fixing global setTimeout/clearTimeout issues

blimmer added a commit to blimmer/xstate that referenced this issue Dec 7, 2020
@blimmer
Copy link
Contributor Author

blimmer commented Dec 7, 2020

For those linked here from the changelog, we decided to call the global methods directly as @Andarist recommended. More details available in the PR comments: #1704

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

Successfully merging a pull request may close this issue.

3 participants