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

Jest not working with 2.0.0-alpha.2 #236

Closed
anthonyvialleton opened this issue Jul 18, 2018 · 26 comments
Closed

Jest not working with 2.0.0-alpha.2 #236

anthonyvialleton opened this issue Jul 18, 2018 · 26 comments

Comments

@anthonyvialleton
Copy link

anthonyvialleton commented Jul 18, 2018

Hello,

In order to get the fix from Google phones I upgraded to 2.0.0-alpha.2 but now I face an other issue.
My unit tests are failing when I test a shallow rendering of a component which imports my utils functions wich import bowser.
If I switch back to the 2.0.0-alpha.1 everything is ok...

I use :

  • Jest 22.4.3
  • Enzyme 3.3.0
  • React 16.3.1

Here is the Jest's error stacktrace :

Test suite failed to run
    /.../fe-react/node_modules/bowser/src/bowser.js:7
    import Parser from './parser';
    ^^^^^^

    SyntaxError: Unexpected token import

       8 |    */
       9 |   static isTabletOrAbove() {
    > 10 |     if (!window) { return false; }
      11 |     const browser = bowser.getParser(window.navigator.userAgent);
      12 |     return browser && (browser.is('tablet') || browser.is('mobile'));
      13 |   }

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:316:17)
      at Object.<anonymous> (src/shared/util/device.js:10:15)

My Jest transformer configuration is configured to ignore node_modules as follow :

 "jest": {
    "collectCoverageFrom": [
      "src/**/*.{js,jsx,mjs}"
    ],
    "setupFiles": [
      "<rootDir>/jest/polyfills.js",
      "<rootDir>/src/setupTests.js"
    ],
    "testMatch": [
      "<rootDir>/src/**/__tests__/**/*.{js,jsx,mjs}",
      "<rootDir>/src/**/?(*.)(spec|test).{js,jsx,mjs}"
    ],
    "testEnvironment": "jsdom",
    "testURL": "http://localhost",
    "transform": {
      "^.+\\.(js|jsx|mjs)$": "<rootDir>/node_modules/babel-jest",
      "^.+\\.css$": "<rootDir>/jest/cssTransform.js",
      "^(?!.*\\.(js|jsx|mjs|css|json)$)": "<rootDir>/jest/fileTransform.js"
    },
    "transformIgnorePatterns": [
      "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$"
    ],

so I'm not really understanding what happens there

@lancedikson
Copy link
Collaborator

Hi, @anthonyvialleton. Thanks for the report. It seems that Jest (or, basically, the testing environment) doesn't work with ES2015 imports.
Do you have any pre-build stage before Jest runs tests for the app? Any babel transpiling running before it? If so, please, try to include /node_modules/bowser/src to transpiling process as well, since those modules are written with plain ES2015.
If you use webpack, please, make sure that the exclude rule for babel-loader doesn't contain bowser, like this:

exclude: /node_modules(?!(\/|\\)bowser)/,

Please, let me know if it works for you.

@lancedikson
Copy link
Collaborator

@anthonyvialleton, just noticed your update with the configuration for Jest. It seems you should try to fix the transformIgnorePatterns using the regular expression, I shared above. So, I would try smth like this: node_modules(?!(\/|\\)bowser).+\.(js|jsx|mjs)$

@anthonyvialleton
Copy link
Author

Hi @lancedikson,

Here is my webpack babel-loader config :

{
          test: /\.js?$ |.jsx?$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          options: {
            plugins: [
              require.resolve('babel-plugin-transform-class-properties'),
              require.resolve('babel-plugin-transform-decorators-legacy'),
              require.resolve('babel-plugin-transform-decorators-legacy'),
              require.resolve('babel-plugin-transform-runtime'),
            ],
            presets: [
              require.resolve('babel-preset-env'),
              require.resolve('babel-preset-react'),
              require.resolve('babel-preset-stage-0'),
            ],
          },
        },

I tried this transformIgnorePatterns regex Jest config :

 "transformIgnorePatterns": [
      "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$",
      "node_modules(?!(\/|\\)bowser).+\\.(js|jsx|mjs)$"
    ],

But it fails when running tests :

  SyntaxError: Invalid regular expression: /[/\\]node_modules[/\\].+\.(js|jsx|mjs)$|node_modules(?!(/|\)bowser).+\.(js|jsx|mjs)$/: Unterminated group
        at new RegExp (<anonymous>)

      at shouldTransform (node_modules/jest-runtime/build/script_transformer.js:466:31)

@lancedikson
Copy link
Collaborator

@anthonyvialleton I guess, you should replace "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$", by "node_modules(?!(\/|\\)bowser).+\\.(js|jsx|mjs)$". I'm not sure if you have to fix babel-loader as well, since I'm not aware of how it's used — before Jest or after.

@lancedikson
Copy link
Collaborator

I'll try to make it easier with splitting the compiled file into 2 pieces: the one with polyfills and another one with the whole bowser. It would help you, just to include the compiled one, but without polyfills.

@aknuds1
Copy link
Contributor

aknuds1 commented Jul 22, 2018

I also have this problem with the latest version of bowser, that it uses an import syntax that Node (v10.7) doesn't support:

~/Projects/example/node_modules/bowser/src/bowser.js:7
import Parser from './parser';

I fixed it by importing 'bowser/dist/bowser.compiled' instead. Should I use the aforementioned file or 'bowser/compiled' if I don't want to transpile my server-side JavaScript? I feel as if it shouldn't be necessary to use Babel on the server side.

@lancedikson
Copy link
Collaborator

Yeah, definitely! You should use bowser/compiled since alpha.2 release.

@lancedikson
Copy link
Collaborator

@anthonyvialleton, I have good news. No need to include bowser in your building process. Just use require('bowser/es5') file to have all needed stuff without polyfills being included.
Let me know if you have any troubles with it still.

@anthonyvialleton
Copy link
Author

Effectively importing bowser in that way solved the issue :

import bowser from 'bowser/compiled';

Thanks

@lancedikson
Copy link
Collaborator

@anthonyvialleton please, be careful with compiled. Now it's bowser/bundled since alpha.3 and I believe it will be so in the future releases. Sorry for bothering with this changes, it's still on alpha stage and I'm trying different names and approaches to make it more suitable. So, you'd better upgrade on alpha.3 and use either bowser/bundled or bowser/es5. I guess both will work for you :)
Have a nice day!

@anthonyvialleton
Copy link
Author

@lancedikson hope you finally have something suitable then ;)

Thanks !

@anthonyvialleton
Copy link
Author

anthonyvialleton commented Jul 26, 2018

Using bowser/bundled now makes my Uglify fail...

 ERROR in admin.working-hours.bundle.js from UglifyJs
    Unexpected token: name (Bowser) [./~/bowser/src/bowser.js:16,0][bundle.js:512,6]

:(

@lancedikson
Copy link
Collaborator

Hmm, it seems, you're using require('bowser') or require('bowser/src/bowser'), since the logger refers to the source file. It should be fine either with require('bowser/bundled') or require('bowser/es5'). Do you mind sharing some piece of code where you require bowser?

@anthonyvialleton
Copy link
Author

anthonyvialleton commented Jul 26, 2018

No I'm not...

// @flow
import bowser from 'bowser/bundled';

export default class Device {
  /**
   * Tablet or mobile platform detector
   * @returns {boolean}
   */
  static isTabletOrAbove() {
    if (!window) { return false; }
    const browser = bowser.getParser(window.navigator.userAgent);
    return browser && (browser.is('tablet') || browser.is('mobile'));
  }

  /**
   * Mobile only platform detector
   * @returns {boolean}
   */
  static isMobile() {
    if (!window) { return false; }
    const browser = bowser.getParser(window.navigator.userAgent);
    return browser && browser.is('mobile');
  }
}

Same using bowser/es5

@lancedikson
Copy link
Collaborator

Ok, for some reason UglifyJS thinks that your project imports bowser as it is and requires the source files. So, the exception is not caused by exactly this piece of code, but by some building system, which takes sources instead of the bundled files.
What kind of building system you have? I guess it's Webpack? What command do you run when you get this exception from Uglify? Is there any other place where you referred to bowser?

@anthonyvialleton
Copy link
Author

No I'm not using Bowser anywhere else and my production Webpack UglifyJS config is :

configs.push(webpackMerge(commonConfig, {
        plugins: [
          new webpack.LoaderOptionsPlugin({
            minimize: true,
            debug: false,
          }),
          new webpack.DefinePlugin({
            'process.env': {
              NODE_ENV: JSON.stringify('production')
            }
          }),
          new webpack.optimize.UglifyJsPlugin({
            beautify: false,
            mangle: {
              screw_ie8: true,
              keep_fnames: true,
            },
            compress: {
              screw_ie8: true,
            },
            comments: false,
            sourceMap: true,
          }),
        ],
      }));

@lancedikson
Copy link
Collaborator

lancedikson commented Jul 26, 2018

Hmm, ok, still not clear. Let's debug :) Could you, please, open your app-name/node_modules/bowser/src/bowser.js, edit it and add such kind of string: console.log(module.parent); as the very first line of the file and then run webpack building. It would help us to see what is the parent module that requires bowser's sources, and maybe find a proper solution.

@anthonyvialleton
Copy link
Author

anthonyvialleton commented Jul 26, 2018

I can't see the console.log in terminal, it's like Webpack is not showing it...

Here is my build-js-prod yarn command :

webpack --display-error-details --env=prod --progress --profile --colors

I tried adding --debug but still don't see the console.log nor console.error.

I figured out that, commenting the bowser import on my file wasn't enough to stop the error. I had to yarn remove the dependency. But I exclude NODE_MODULES from the preprocessors...

Here is my Webpack core configuration :

const coreConfig = () => {
  return {
    resolve: {
      extensions: ['.jsx', '.js', 'css'],
      modules: [NODE_MODULES_PATH],
    },
    module: {
      rules: [
        {
          test: /\.(js|jsx|mjs)$/,
          exclude: /node_modules/,
          loader: 'eslint-loader',
          enforce: 'pre',
          options: {
            configFile: path.resolve('.eslintrc'),
            emitWarning: true,
            fix: false,
          },
        },
        {
          test: /\.js?$ |.jsx?$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          options: {
            plugins: [
              require.resolve('babel-plugin-transform-class-properties'),
              require.resolve('babel-plugin-transform-decorators-legacy'),
              require.resolve('babel-plugin-transform-decorators-legacy'),
              require.resolve('babel-plugin-transform-runtime'),
            ],
            presets: [
              require.resolve('babel-preset-env'),
              require.resolve('babel-preset-react'),
              require.resolve('babel-preset-stage-0'),
            ],
          },
        },
        {
          test: /\.css$/,
          loader: 'style-loader!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
        },
        {
          test: /\.(jpg|png|gif)$/,
          loader: 'file-loader',
        },
        {
          test: /\.(woff|woff2|eot|ttf|svg)$/,
          loader: 'url-loader?limit=100000',
        },
      ],
    },
    plugins: [
      // Add module names to factory functions so they appear in browser profiler.
      new webpack.NamedModulesPlugin(),
      // Makes some environment variables available to the JS code, for example:
      // if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
      // new webpack.DefinePlugin({
      //   'process.env': {
      //     BROWSER: JSON.stringify(true),
      //     NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'dev'),
      //   },
      // }),
      // Watcher doesn't work well if you mistype casing in a path so we use
      // a plugin that prints an error when you attempt to do this.
      // See https://github.com/facebookincubator/create-react-app/issues/240
      new CaseSensitivePathsPlugin(),
      // If you require a missing module and then `npm install` it, you still have
      // to restart the development server for Webpack to discover it. This plugin
      // makes the discovery automatic so you don't have to restart.
      // See https://github.com/facebookincubator/create-react-app/issues/186
      new WatchMissingNodeModulesPlugin(NODE_MODULES_PATH),
    ],
  };
};

@lancedikson
Copy link
Collaborator

@anthonyvialleton, that's weird. Ok, you can try to debug the building process using --inspect flag for Node (https://webpack.js.org/contribute/debugging/#devtools), putting debugger somewhere in bowser/src/bowser.js and using DevTools. Using this you can realize what is the parent (or caller) of the source file. You don't need those nightly builds as they write in docs if you have Node 8 at least.
If you want, you can create a repo to reproduce the error with the minimal set of your environment, which you could share with me and I'll try to investigate the problem.

@anthonyvialleton
Copy link
Author

anthonyvialleton commented Jul 30, 2018

@lancedikson When trying to run the debugger using node-nightly --inspect ./node_modules/bowser/src/bowser.js

I get this error :

Debugger listening on ws://127.0.0.1:9229/af5c4994-3143-4a72-b4b3-f0abeadd06c7
For help, see: https://nodejs.org/en/docs/inspector
/../node_modules/bowser/src/bowser.js:9
import Parser from './parser';
       ^^^^^^

SyntaxError: Unexpected identifier
    at new Script (vm.js:72:7)
    at createScript (vm.js:234:10)
    at Object.runInThisContext (vm.js:286:10)
    at Module._compile (internal/modules/cjs/loader.js:657:28)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
    at startup (internal/bootstrap/node.js:266:19)

Remote debugging shutdowns directly..

@lancedikson
Copy link
Collaborator

@anthonyvialleton, yes, and this is normal. You don't have to debug the source files of bowser. It's better to debug the building system, your webpack build to be exact. I recommend you to put a debugger; statement as the very first line of node_modules/bowser/src/bowser.js file and then run node --inspect ./node_modules/webpack/bin/webpack.js and pass the needed env vars and configs that you need for webpack to build the project. Don't forget to use Chrome Remote Debugging to connect to created debugging server ws://127.0.0.1:9229/af5c4994-3143-4a72-b4b3-f0abeadd06c7. Then you will see when it stops as soon as the bowser/src/bowser.js is reached and it will be available to see, who is the caller of the source file, even though it should be called at all.

@anthonyvialleton
Copy link
Author

@lancedikson sadly it takes too much time to build and the debugger is never triggered on the debugging server Chrom Dev Tools console... A pain in the ass tbh to debug...

@lancedikson
Copy link
Collaborator

@anthonyvialleton, gotcha. I think you could have a workaround. Try redefining main property in the bowser's package.json in node_modules folder from ./src/bowser.js to ./es5.js. If it helps, I will release a new version of bowser with es5 as the main file.

@anthonyvialleton
Copy link
Author

@lancedikson replacing /src/bowser.js by ./es5.js worked ! Also my Jest unit tests are working fine. Please release the change and notify me when it's up.
By the way I hope that you won't change it on the next versions :s

Thanks for the support !

@lancedikson
Copy link
Collaborator

@anthonyvialleton, cool! I'm glad to hear that. Yeah, the next release will definitely change that problem. It'll be today or tomorrow, I guess.

Have a great day!

@lancedikson
Copy link
Collaborator

@anthonyvialleton, you can subscribe to this issue: #239 and you will get a notification, when it's closed :)

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

No branches or pull requests

3 participants