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

URL behaves differently when run with jest #10045

Closed
fredefox opened this issue May 15, 2020 · 17 comments
Closed

URL behaves differently when run with jest #10045

fredefox opened this issue May 15, 2020 · 17 comments

Comments

@fredefox
Copy link

🐛 Bug Report

The object thrown by the constructor of URL is not an instance of Error.

To Reproduce

Create a file error.test.js with the following contents:

#!/usr/bin/env node
try {
  new URL("not_a_url");
} catch (anything) {
  process.exit(anything instanceof Error ? 0 : 1);
}

If you run node error.test.js the program exits successfully. However, if you use jest to run this file you get:

§ jest
  ●  process.exit called with "1"

      3 |   new URL("not_a_url");
      4 | } catch (anything) {
    > 5 |   process.exit(anything instanceof Error ? 0 : 1);
        |           ^
      6 | }
      7 |

      at Object.exit (error.test.js:5:11)

 RUNS  ./error.test.js

Expected behavior

I expect the error raised by the call to URL to be an instance of Error.

envinfo

  System:
    OS: macOS Mojave 10.14.6
    CPU: (8) x64 Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
  Binaries:
    Node: 12.1.0 - /usr/local/bin/node
    Yarn: 1.22.0 - ~/.yarn/bin/yarn
    npm: 6.13.7 - /usr/local/bin/npm
@fredefox
Copy link
Author

Is jest perhaps not using the same implementation of URL as when I run node directly?

@fredefox
Copy link
Author

Indeed printing out URL.toString() gives different results for the two different invocations.

@carsonreinke
Copy link

@fredefox looks like you are correct, whatwg-url is being used (polyfill for URL), but that is not the issue.

Instead, it is related to #2549 (via #6788 (comment)).

@fredefox
Copy link
Author

This does look like it could be a duplicate. Yes. Thanks @carsonreinke. What I'm not really getting is what it has to do with instanceof. I'm not aware that it's possible to override built-in operators. Isn't the problem more that the Jest runtime mutates the global environment.

@carsonreinke
Copy link

carsonreinke commented Jul 22, 2020

@fredefox it is really strange, I have not really gotten to the bottom of it, but I did try using https://www.npmjs.com/package/jest-runner-mocha and it does NOT exhibit that behavior.

@lukasoppermann
Copy link

I am getting TypeError: URL is not a constructor in my jest test, while it works fine in node. Is this perhaps related?

@fredefox
Copy link
Author

I am getting TypeError: URL is not a constructor in my jest test, while it works fine in node. Is this perhaps related?

I don't think that's related, no.

@SimenB
Copy link
Member

SimenB commented Aug 10, 2020

This is #2549, yeah

@fredefox it is really strange, I have not really gotten to the bottom of it, but I did try using npmjs.com/package/jest-runner-mocha and it does NOT exhibit that behavior.

Yeah, this behavior is specific to Jest since we use the vm module to create sandboxes - mocha runs all the tests in the same context.

Latest update to #2549 is essentially nodejs/node#31852

@SimenB SimenB closed this as completed Aug 10, 2020
@carsonreinke
Copy link

Thanks @SimenB

@carsonreinke
Copy link

@fredefox I believe a good work around for this problem, wherever you are using URL you could specifically import instead of relying on it being globally defined.

@fredefox
Copy link
Author

@fredefox I believe a good work around for this problem, wherever you are using URL you could specifically import instead of relying on it being globally defined.

I wasn't aware that I could import built-ins. Would you happen to know how you would modify my example to circumvent this? If you don't know off the top of your head it's ok.

@carsonreinke
Copy link

@fredefox so I think as simple as adding const URL = require('url'); wherever you are using URL.

Here is an example:

const URL = require('url');

try {
    new URL("not_a_url");
}
catch (anything) {
    console.log(anything instanceof TypeError); //will be true
}

try {
    new global.URL("not_a_url");
}
catch (anything) {
    console.log(anything instanceof TypeError); //will be false
}

I'm not really sure how this would impact the polyfill though, probably nothing since this is a Node/Jest only problem.

@lukasoppermann
Copy link

However, when I tried it I found that the resulting object is actually not the same, as there is not SearchParameters object

@carsonreinke
Copy link

@lukasoppermann Something like const URLSearchParams = require('url').URLSearchParams, if you look at require('url') is actually this:

{
  Url: [Function: Url],
  parse: [Function: urlParse],
  resolve: [Function: urlResolve],
  resolveObject: [Function: urlResolveObject],
  format: [Function: urlFormat],
  URL: [Function: URL],
  URLSearchParams: [Function: URLSearchParams],
  domainToASCII: [Function: domainToASCII],
  domainToUnicode: [Function: domainToUnicode],
  pathToFileURL: [Function: pathToFileURL],
  fileURLToPath: [Function: fileURLToPath]
}

@fredefox
Copy link
Author

Ah. Thank you very much @carsonreinke! That'll do it.

@fredefox
Copy link
Author

fredefox commented Aug 11, 2020

And re the "not the same" part. Just to expand on what @carsonreinke already wrote. In his example he's shadowing the built-in URL, but the thing doing the shadowing, is not the same as the thing it is shadowing. The thing he is shadowing is present at URL.URL.

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants