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

Absolute imports does not resolve with NODE_PATH in 5+ #8481

Closed
johanbook opened this issue Sep 2, 2020 · 11 comments
Closed

Absolute imports does not resolve with NODE_PATH in 5+ #8481

johanbook opened this issue Sep 2, 2020 · 11 comments
Labels
stage: wontfix Cypress does not regard this as an issue or will not implement this feature topic: imports topic: preprocessors 🔧

Comments

@johanbook
Copy link

johanbook commented Sep 2, 2020

Current behavior:

When starting Cypress with

NODE_PATH=ui/src cypress open

it is unable to resolve absolute imports

Webpack Compilation Error
./cypress/integration/cart/utils.js
Module not found: Error: Can't resolve 'ducks/cart' in '/home/pong/e2e/cypress/integration/cart'
...

My code is

import { cartOperations } from "ducks/cart";
...

Desired behavior:

Imports resolve correctly. This worked in 4.12.1.

Test code to reproduce

Will create a minimal working example if needed and deemed to be an issue.

Versions

Cypress 5.1.0
Node 14.5.0
OS: Ubuntu

@borecz
Copy link

borecz commented Sep 2, 2020

I am having similar issue,

I have a this folder structure:

root

- cypress
-- integration
-- etc
- webpack.config
- tsconfig

webpack.config

var path = require("path");
module.exports = {
  resolve: {
    extensions: [".ts", ".js"],
    alias: {
      "@config": path.resolve(__dirname, "./config"),
      "@cypress": path.resolve(__dirname, "cypress"),
      "@fixtures": path.resolve(__dirname, "cypress/fixtures/"),
      "@helpers": path.resolve(__dirname, "cypress/helpers/"),
      "@integration": path.resolve(__dirname, "cypress/integration/"),
      "@pages": path.resolve(__dirname, "cypress/Pages/"),
    },
  },
};

ts-config

{
  "compilerOptions": {
    "target": "ES6",
    "module": "CommonJS",
    "skipLibCheck": true,
    "noImplicitAny": false,
    "strict": true,
    "allowJs": false,
    "removeComments": true,
    "baseUrl": ".",
    "types": [
      // load Cypress global type
      "cypress",
      "node"
    ],
    "outDir": "./compiled_JS",
    "lib": ["es6", "ESNext", "dom", "ES5"],
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "paths": {
      "@config/*": ["config/*"],
      "@cypress/*": ["cypress/*"],
      "@fixtures/*": ["cypress/fixtures/*"],
      "@helpers/*": ["cypress/helpers/*"],
      "@integration/*": ["cypress/integration/*"],
      "@pages/*": ["cypress/Pages/*"]
    }
  },
  "include": ["./**/*.ts", "./*", "../*"]
}

I've tried really many options but result is always, pretty much this

image

Could you please share a working configuration for using path aliases on the latest Cypress with built in support for TS?

resources like this are outdated: https://glebbahmutov.com/blog/using-ts-aliases-in-cypress-tests/

@bahmutov
Copy link
Contributor

bahmutov commented Sep 2, 2020

Can you please prepare a repo with reproducible example? We have switched from browserify to webpack for bundling in v5, thus some of the resolution logic might have changed.

@johanbook
Copy link
Author

johanbook commented Sep 3, 2020

Here is an example where is resolves correctly in 4.12.1 but not in 5.1.0.

@jarrietas
Copy link

Having the same issue.
Setting NODE_PATH=./ used to work in cypress 4 (to support absolute paths).
No longer working when updated to 5.1 version.

@lenymo
Copy link

lenymo commented Dec 10, 2020

Any update on this? Anyone have a workaround?

I'm currently holding off on updating because I've got a large codebase which uses absolute imports and I'd prefer not to have to refactor the entire thing to get cypress tests to run.

@jennifer-shehane
Copy link
Member

NODE_PATH is not supported in webpack by default as it was in browserify. Webpack's reasoning is that use of NODE_PATH is discouraged: webpack/webpack#4479

NODE_PATH is still supported, but is less necessary now that the Node.js ecosystem has settled on a convention for locating dependent modules. Sometimes deployments that rely on NODE_PATH show surprising behavior when people are unaware that NODE_PATH must be set. Sometimes a module's dependencies change, causing a different version (or even a different module) to be loaded as the NODE_PATH is searched.

It is strongly encouraged to place dependencies in the local node_modules folder. These will be loaded faster, and more reliably.

See the workaround below for this.

Reproducible example

NODE_PATH=ui/src cypress open

cypress/integration/spec.js

import {icecone} from "duck";

it('works', () => {
  icecone();
})

ui/src/duck/index.js

export const icecone = () => console.log("I take two");

4.12.1

Screen Shot 2020-12-10 at 2 23 04 PM

6.1.0

Screen Shot 2020-12-10 at 2 09 11 PM

Resolution / Workaround

Extend you webpack.config options resolve.modules to look for the NODE_PATH:

webpack.config.js

const cwd = process.cwd();
const path = require('path');

const nodePath = process.env.NODE_PATH || 'src';

module.exports = {
  resolve: {
    modules: ['node_modules', path.resolve(cwd, nodePath)],
  }
}

cypress/plugins/index.js

Pass in the webpack options to cypress. This requires use of @cypress/webpack-preprocessor: https://github.com/cypress-io/cypress/tree/master/npm/webpack-preprocessor#options

npm install --save-dev @cypress/webpack-preprocessor @babel/core @babel/preset-env babel-loader webpack
const webpackPreprocessor = require('@cypress/webpack-preprocessor')

module.exports = (on) => {
  const options = {
    webpackOptions: require('../../webpack.config'),
    watchOptions: {},
  }

  on('file:preprocessor', webpackPreprocessor(options))
}

@jennifer-shehane jennifer-shehane changed the title Absolute imports does not resolve in 5.1 Absolute imports does not resolve with NODE_PATH in 5+ Dec 10, 2020
@jennifer-shehane jennifer-shehane added the stage: wontfix Cypress does not regard this as an issue or will not implement this feature label Dec 10, 2020
@lenymo
Copy link

lenymo commented Dec 10, 2020

Thank you Jennifer, I shall look into those options.

@Nenry
Copy link

Nenry commented Dec 14, 2020

Wanted to leave a comment for anyone that might run into this. I also ran into this issue while using jsconfig as recommended by create-react-app. (https://create-react-app.dev/docs/importing-a-component/).
This error doesn't occur in Cypress V4, but is present in V5 and V6.

This is the working fix for me since I was using create-react-app.

  • No need to create the webpack.config

  • Also note for some reason cypress does not like this type of import style after you use this workaround (I think it has to do something with findWebpack.cleanForCypress:
    export { default as SomeCommands } from "./SomeCommands"

  • Just change it to regular import SomeCommands from "./SomeCommands"

The workaround for create-react-app/react-scripts
Copy and paste from https://github.com/cypress-io/cypress/blob/master/npm/webpack-preprocessor/examples/react-app/cypress/plugins/index.js, but changed const webpackPreprocessor = require("@cypress/webpack-preprocessor")

const findWebpack = require("find-webpack");
const webpackPreprocessor = require("@cypress/webpack-preprocessor");


module.exports = (on) => {
  const webpackOptions = findWebpack.getWebpackOptions();

  if (!webpackOptions) {
    throw new Error("Could not find Webpack in this project 😢");
  }

  const cleanOptions = {
    reactScripts: true
  };

  findWebpack.cleanForCypress(cleanOptions, webpackOptions);

  const options = {
    webpackOptions,
    watchOptions: {}
  };

  on("file:preprocessor", webpackPreprocessor(options));
};

@lenymo
Copy link

lenymo commented Dec 15, 2020

Thanks for sharing @Nenry that worked very nicely for me. Up and running using create-react-app with absolute imports.

@jmcollin78
Copy link

Many thaks @jennifer-shehane for your help.
When trying in Cypress 7.2.0 your solution, I ran into this error:

TypeError: err.replace is not a function    at cleanseError (/Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/@cypress/webpack-preprocessor/dist/index.js:272:16)
    at Array.map (<anonymous>)
    at Watching.handle [as handler] (/Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/@cypress/webpack-preprocessor/dist/index.js:175:22)
    at /Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/webpack/lib/Watching.js:204:9
    at Hook.eval [as callAsync] (eval at create (/Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
    at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (/Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/tapable/lib/Hook.js:18:14)
    at Watching._done (/Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/webpack/lib/Watching.js:201:28)
    at /Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/webpack/lib/Watching.js:129:21
    at Compiler.emitRecords (/Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/webpack/lib/Compiler.js:862:39)
    at /Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/webpack/lib/Watching.js:107:22
    at /Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/webpack/lib/Compiler.js:844:14
    at Hook.eval [as callAsync] (eval at create (/Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
    at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (/Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/tapable/lib/Hook.js:18:14)
    at /Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/webpack/lib/Compiler.js:841:27
    at /Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/neo-async/async.js:2818:7
    at done (/Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/neo-async/async.js:3522:9)
    at alreadyWritten (/Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/webpack/lib/Compiler.js:673:8)
    at /Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/webpack/lib/Compiler.js:761:19
    at /Users/jmcollin/SugarSync/Projets/cypress-cld-apps/node_modules/webpack/node_modules/graceful-fs/graceful-fs.js:123:16
    at /Users/jmcollin/Library/Caches/Cypress/7.2.0/Cypress.app/Contents/Resources/app/packages/server/node_modules/graceful-fs/graceful-fs.js:90:16
    at FSReqCallback.readFileAfterClose [as oncomplete] (internal/fs/read_file_context.js:63:3)

Any clues ?

@jennifer-shehane
Copy link
Member

@jmcollin78 I didn't run into this error when rerunning my example workaround above. Can you open a new issue with a reproducible example? It's likely something extra in your example that I don't have. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stage: wontfix Cypress does not regard this as an issue or will not implement this feature topic: imports topic: preprocessors 🔧
Projects
None yet
Development

No branches or pull requests

8 participants