Jest: babel-jest can't handle template strings within a require statement in with --watch flag

Created on 13 Dec 2018  路  13Comments  路  Source: facebook/jest

馃悰 Bug Report

When running require within a block of code that contains a template string (e.g. require(images/${imageURL})), babel-jest fails to resolve the template string properly when running jest --watch. It works fine without the --watch flag.

To Reproduce

Run jest --watch with babel-jest set as the transformer on a file that contains the following:

const ImageLink = ({ linkPath, linkLabel, imageSource }: ImageLinkProps) => (
  <Link to={linkPath}>
    <img alt={`Navigation link to ${linkLabel}`} src={require(`$images/${imageSource}`)} />
    <span>{linkLabel}</span>
  </Link>
);

Expected behavior

The above code is valid and works without issue when transformed by babel-jest without the --watch flag. I expect it to work without issue with --watch set as well. However, I currently get the following error from jest (which in turn doesn't run, due to a non-existent file):

Could not locate module $images/${imageSource} mapped as:
/home/thisissami/code/s2sFrontEnd/static/images/${imageSource}.

Please check your configuration for these entries:
{
  "moduleNameMapper": {
    "/^\$images(.*)/": "/home/thisissami/code/s2sFrontEnd/static/images$1"
  },
  "resolver": null
}

This clearly means that babel-jest is not resolving the template string within the require, and is rather treating the template string as a normal string. When changing the above code to the following, babel-jest transforms without issue with the --watch mode:

const ImageLink = ({ linkPath, linkLabel, imageSource }: ImageLinkProps) => {
  const src = `$images/${imageSource}`;

  return (
    <Link to={linkPath}>
      <img alt={`Navigation link to ${linkLabel}`} src={require(src)} />
      <span>{linkLabel}</span>
    </Link>
  );
};

Run npx envinfo --preset jest

Paste the results here:

  System:
    OS: Linux 4.15 Pop!_OS 18.04 LTS
    CPU: (8) x64 Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
  Binaries:
    Node: 10.8.0 - ~/.nvm/versions/node/v10.8.0/bin/node
    npm: 6.4.0 - ~/.nvm/versions/node/v10.8.0/bin/npm
  npmPackages:
    jest: ^23.5.0 => 23.6.0
Bug Needs Repro

Most helpful comment

Using --watchAll works correctly.

All 13 comments

Would you mind putting up a quick reproduction that does not use react but still show the error?

I have created a reproduction may related to this issue: https://github.com/otakustay/jest-bug-demo

yarn
jest --watch

jest will be success while jest --watch will fail

This is also referenced in #4552

The same thing happens if using the --findRelatedTests cli option. Any updates?

@SimenB @thymikee any updates? There's been a reproduction for several months now.

Here's another reproduction using React. https://codesandbox.io/s/jest-test-wylir If you run that with jest --watch it will not work. Adding this to update that using newer ES dynamic imports, the same thing happens. it is not limited to just require.

@SimenB @thymikee if you guys can point me to where the relevant files would be, I'd be happy to take a look and see if I fix this bug. It's really frustrating to have to have 2 different sets of code (one for running the server, and one for testing) that we have to keep commenting out/in - depending on what our use case is.

The requirement by jest --watch to define the url in a separate variable before requiring/importing it makes it so that webpack is unable to resolve things, as it interprets an alias in the url (which we are using) as an actual destination.

Hi @thisissami, I've just taken a look at this.
@otakustay's repo seems like a different issue and it has been discussed in #4552 already.
Unfortunately, your Codesandbox contains a lot of incompatible dependencies, such as Jest 24 and Babel 6, and lots of extra code, so I'm not sure how useful it is to debug this. I took the time to make a proper minimal repro that I think describes the same issue: https://github.com/jeysal/jest-7511-repro
I haven't had the time to dive into this much deeper though. It's clearly caused by configuring a moduleNameMapper and adding an import that it applies (doesn't happen otherwise), but I'm not sure why this matters or why it doesn't crash otherwise (no idea what code decides not to detect a template string as a dependency when doing static analysis to figure out dependencies for watch/findRelatedTests).
If you want to have a go, the interesting places are probably jest-haste-map and its dependencyExtractor (where the files are statically searched for dependencies), SearchSource where the findRelatedTests operation is performed, and jest-resolve-dependencies, which is used there, and jest-resolve, which is in turn used there and considers the moduleNameMapper option.

Thanks for the info @jeysal. I've found a workaround in the meantime that allows our codebase to not need to change between running jest --watch and everything else. For the files in question, just removing the alias and instead having a ../../../../folder1/folder2/file does the trick. I'm accordingly not going to bother, given that there's a large number of possible locations.

I do find it a bit weird that running jest without the --watch flag works without issue though. I wonder what changes there that makes aliases problematic.

I think after playing around with various things, the bigger issue is the alias. i tried breaking things out into 2 normal strings being concatenated together (before trying this workaround), and the alias wouldn't work with --watch mode using that approach either.

I do find it a bit weird that running jest without the --watch flag works without issue though. I wonder what changes there that makes aliases problematic.

The static analysis, trying to figure out dependencies between files in order to determine which tests relate to SCM-changed files and need to be rerun, is probably the thing happening only in watch mode that breaks down here.

same problem here

You can verify the above by running jest --only-changed (or jest -o for short) which does the same thing --watch does when it comes to VCS

Using --watchAll works correctly.

Was this page helpful?
0 / 5 - 0 ratings