enzymejs / enzyme

JavaScript Testing utilities for React
https://enzymejs.github.io/enzyme/
MIT License
19.96k stars 2.01k forks source link

Cannot find module 'cheerio' from 'node_modules/enzyme/build/Utils.js' #2518

Open mmarshad opened 3 years ago

mmarshad commented 3 years ago

I just start receiving this message to my unit tests today, although it was working fine before

Cannot find module 'cheerio' from 'node_modules/enzyme/build/Utils.js'

Require stack:
  node_modules/enzyme/build/Utils.js
  node_modules/enzyme/build/ShallowWrapper.js
  node_modules/enzyme-to-json/utils.js
  node_modules/enzyme-to-json/createSerializer.js
  node_modules/enzyme-to-json/serializer.js

  at Resolver.resolveModule (node_modules/jest-runtime/node_modules/jest-resolve/build/index.js:306:11)
  at Object.<anonymous> (node_modules/enzyme/src/Utils.js:9:1)

Is there anything changed in serlizer.js? "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.6", "enzyme-to-json": "^3.6.1",

ljharb commented 3 years ago

enzyme-to-json is not maintained by the enzyme team, so you'd have to ask them.

Mahdiyeh commented 3 years ago

Same here for me:

` Cannot find module 'cheerio' from 'node_modules/enzyme/build/Utils.js'

Require stack:
  node_modules/enzyme/build/Utils.js
  node_modules/enzyme/build/ReactWrapper.js
  node_modules/enzyme/build/index.js

  at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:306:11)
  at Object.<anonymous> (node_modules/enzyme/build/Utils.js:80:16)
  `

My dependencies: "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5"

ljharb commented 3 years ago

Please try pinning cheerio to =1.0.0.rc-3, ensure it's installed, and let me know if the issue persists.

rxgx commented 2 years ago

Adding an override doesn't fix the issue with enzyme incorrectly using a loose RC pattern for a hard dependency.

  "overrides": {
    "enzyme": {
      "cheerio": "1.0.0.rc-3"
    }
  },

Cheerio is now a dual CommonJS and ESM module. That means that deep imports will now fail in newer versions of Node. https://github.com/cheeriojs/cheerio/releases/tag/v1.0.0-rc.11

ljharb commented 2 years ago

@rxgx while that should work - file an issue with npm if it doesn't - simply adding "cheerio": "=1.0.0.rc-3" to your devDependencies should be sufficient, no overrides required.

rxgx commented 2 years ago

@ljharb what old version of npm are you using?

npm ERR! code EINVALIDTAGNAME
npm ERR! Invalid tag name "=1.0.0.rc-3" of package "cheerio@=1.0.0.rc-3": Tags may not have any characters that encodeURIComponent encodes.
ljharb commented 2 years ago

works fine with every version of npm, through the latest. That's a version specifier, not a tag name.

It's what the next release of enzyme will use: https://github.com/enzymejs/enzyme/blob/master/packages/enzyme/package.json#L42

rxgx commented 2 years ago

Is it possible that this version is missing from the registry? I get these errors even with rm node_modules and npm cache verify. OR something up with npm itself

lerna notice cli v4.0.0
lerna ERR! cheerio: No matching version found for cheerio@1.0.0.rc-3.
lerna ERR!     at module.exports (/Users/rgasparini/Code/monorepo/node_modules/npm-pick-manifest/index.js:209:23)
lerna ERR! lerna No matching version found for cheerio@1.0.0.rc-3.
$ npm i -D cheerio@1.0.0.rc-3 
npm ERR! code ETARGET
npm ERR! notarget No matching version found for cheerio@1.0.0.rc-3.
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn't exist.
$ npm i -D cheerio@=1.0.0.rc-3
npm ERR! code EINVALIDTAGNAME
npm ERR! Invalid tag name "=1.0.0.rc-3" of package "cheerio@=1.0.0.rc-3": Tags may not have any characters that encodeURIComponent encodes.
ljharb commented 2 years ago

Is it possible you're not using the public registry? It's quite there: https://unpkg.com/browse/cheerio@1.0.0-rc.3/

rxgx commented 2 years ago

Here's what I originally thought was the resolution before being derailed by the invalid = syntax. I got the hyphen and dots mixed up.

  "overrides": {
    "enzyme": {
      "cheerio": "1.0.0-rc.3"
    }
  },

If you manually change the version of the dependencies or devDependencies, your lock file is unfortunately going to be out of sync.

ljharb commented 2 years ago

The = syntax is a range; overrides takes a specific version - it’s not invalid in general, i just wasn’t providing an override. Overrides should be used only as a last resort.

nspector commented 2 years ago

Looks like the change to pin it here: https://github.com/enzymejs/enzyme/commit/cafdb2b86ed8865527cdd6ae31c42593d3728ceb was never published: https://unpkg.com/browse/enzyme@3.11.0/package.json. Can somebody publish it? Thank you!

ljharb commented 2 years ago

@nspector correct; it hasn't been published yet. it'll be in the next release.

Again, you can get the benefit now merely by doing npm install --save-dev cheerio@=1.0.0-rc.3.

tonnyskk commented 2 years ago

Try lock your cheerio version to 1.0.0-rc.10 E.g. by yarn resolutions. 1.0.0-rc.11 will throw the error.

billnbell commented 2 years ago

This worked for me

   "resolutions": {
+    "cheerio": "1.0.0-rc.10"
   },
richard1230 commented 2 years ago

Same here for me:

` Cannot find module 'cheerio' from 'node_modules/enzyme/build/Utils.js'

Require stack:
  node_modules/enzyme/build/Utils.js
  node_modules/enzyme/build/ReactWrapper.js
  node_modules/enzyme/build/index.js

  at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:306:11)
  at Object.<anonymous> (node_modules/enzyme/build/Utils.js:80:16)
  `

My dependencies: "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5"

Do you resolve this one? I have the same issue

richard1230 commented 2 years ago

This worked for me

   "resolutions": {
+    "cheerio": "1.0.0-rc.10"
   },

which file should it be put?

ljharb commented 2 years ago

@richard1230 in package.json. resolutions only applies to yarn tho.

You should add "cheerio": "=1.0.0-rc.3" to your devDependencies in package.json instead.

billnbell commented 2 years ago

Well devDependencies did not help. When I added "resolutions" it works.

ljharb commented 2 years ago

@devinm-hrbl no.

mjperales commented 2 years ago

This worked perfectly! If you copy/paste the above ☝️ then make sure there isn't a period at the end! That was causing the invalid tag name issue for me

new-carrot commented 2 years ago

I also have this issue. I am using Yarn with workspaces. Normally, after a yarn install, all dependencies are stored in node_modules in the root folder. My tests are inside a subfolder with its own package.json.

So to hot fix the issue temporarily, I run npm i in the subfolder to install all dependencies AGAIN in node_modules in subfolder. I can delete everything in node_modules in subfolder except these three: enzyme, enzyme-adaptor-preact-pure, enzyme-to-json. Then all the tests pass again.

s100 commented 2 years ago

This is happening because in ./build/Utils.js, enzyme is doing this:

https://github.com/enzymejs/enzyme/blob/3d286a4f45f5c1b9c649fd5ee63fe9fd57e0d597/packages/enzyme/src/Utils.js#L11

Notice how this imports a specific internal module from deep inside the guts of cheerio, ./lib/utils.js.

This bypasses the public API of cheerio, which intends for users to either import ... from 'cheerio', or import ... from 'cheerio/lib/slim' only. Bypassing the public API of a package in this way is always hazardous, because it means that if cheerio rearranges its internal modules, this usage will break. This is an anti-pattern, and it is almost never officially supported by the package you're using.

Recently, webpack has started allowing a new field, "exports", to be used in package.json. This is intended to enable package maintainers to have greater control over this kind of direct import, and how Node.js resolves these dependencies. This field allows two things: firstly, an import like 'cheerio/lib/slim' doesn't have to resolve to ./lib/slim.js, it can be made to resolve to anything the maintainers want - this enables maintainers to rearrange their internals without breaking consumers. Secondly, it means all other deep imports like 'cheerio/lib/utils' now deliberately do not work at all. This disables that API bypass anti-pattern, and reduces the public interface of the package to only what the maintainers choose.

cheerio began using "exports" in https://github.com/cheeriojs/cheerio/pull/2508, which went into cheerio@1.0.0-rc.11, which was released on 20 May 2022, thereby officially dropping support for deep imports. I don't know if deep imports were ever officially supported by cheerio, but they are no longer supported. Technically this is a breaking change, but cheerio@1.0.0-rc.11 is only a release candidate, which I'm guessing doesn't have any kind of commitment to avoiding breaking changes, so cheerio is entirely within its rights to do this.

The real problem, then, is that enzyme@3.11.0 specifies a dependency on a range of unstable release candidate versions of cheerio, which can break without warning in exactly this way:

https://github.com/enzymejs/enzyme/blob/6e990c0cef99061006de5a883301d707f32aa6f0/packages/enzyme/package.json#L42

The fix for this is for enzyme to pin to a specific RC of cheerio, which in fact has already been done, in December 2020. However, no new version of enzyme has been released since then.

ljharb commented 2 years ago

The public api of a package is everything reachable inside it, and deep imports are always preferable since they obviate the need for treeshaking.

The exports field is a node thing, webpack just supports it, and rc11 added a breaking change to use it, but as you note, prereleases can have those. Prior to this, this file was absolutely part of the public api of cheerio.

You are also correct that enzyme just needs a release to fix this issue.

s100 commented 2 years ago

@ljharb Is this package still actively maintained?

ljharb commented 2 years ago

@s100 yes, as you can see by my comment yesterday.

s100 commented 2 years ago

@s100 yes, as you can see by my comment yesterday.

Awesome... so, when can we expect a new release with this fix?

ljharb commented 2 years ago

@s100 i don't commit to specific release schedules, and the lack of a release is unrelated to whether the package is maintained.

fengxinhhh commented 2 years ago

Hello, I also found the error: Cannot find module 'cheerio/lib/utils' from 'node_modules/enzyme/build/Utils.js'

Require stack:
  node_modules/enzyme/build/Utils.js
  node_modules/enzyme/build/ReactWrapper.js
  node_modules/enzyme/build/index.js
  src/__tests__/Button/button.test.tsx

My devDependencies list include enzyme are:

"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"enzyme-to-json": "^3.3.5",

So, now we can't solve the problem?

blixt commented 2 years ago

I also ran into this issue and made this PR in the Cheerio repository: https://github.com/cheeriojs/cheerio/pull/2601

Though since it's such a simple function (which could be replaced by /<[a-zA-Z!][^>]*>/.test(str)) that follows a spec and has no need of knowledge of behaviors within Cheerio, one could argue the better solution is to just embed it into Enzyme to avoid depending on the internal structure of another package.

ljharb commented 2 years ago

That’s a fair point. Cheerio could still be used to verify the results of the function in tests.

I’d be happy to accept a PR inlining that function.

hesamhoseinkhani commented 3 weeks ago

@ljharb any updates?