npm / npm/cli

[BUG] Workspaces hoisted package is not resolving to dependent's peer dependencies

Open
#2,989 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Release 7.x
Dominant language
JavaScript
Stars
10.1k
Forks
4.7k
Avg merge
2d 2h
Merged PRs (30d)
19

Description

Current Behavior:

I have a project using multiple workspaces. For simplicity I created a smaller project that reproduces the issue.
I am using @testing-library/react to help with some unit tests, and I have pulled in the required peer dependencies of react and react-dom. Each package is using its own version of React, one is using 17.0.1 and the other 17.0.2. Both are using the same @testing-library/react package version. The hoisted packages are react (17.0.2), react-dom (17.0.2) and @testing-library/react (11.2.5). Package b has its own React versions for react and react-dom in its local node_modules. I have both projects using the @testing-library/react render function in a set of test files. When I run jest on project a, it passes without issue. When I run jest on project b (with its local versions), it fails with the following error:

package-b@1.0.0 test
jest

FAIL tests/components/App.test.tsx
● Console

console.error
  Error: Uncaught [Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app
  See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.]
      at reportException (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:62:24)
      at innerInvokeEventListeners (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:341:9)
      at invokeEventListeners (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
      at HTMLUnknownElementImpl._dispatch (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
      at HTMLUnknownElementImpl.dispatchEvent (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
      at HTMLUnknownElement.dispatchEvent (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34)
      at Object.invokeGuardedCallbackDev (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:3994:16)
      at invokeGuardedCallback (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:4056:31)
      at beginWork$1 (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:23964:7)
      at performUnitOfWork (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:22779:12) Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app
  See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
      at resolveDispatcher (/Users/USER_DIRECTORY/experimental/npm-workspaces/packages/package-b/node_modules/react/cjs/react.development.js:1476:13)
      at Object.useState (/Users/USER_DIRECTORY/experimental/npm-workspaces/packages/package-b/node_modules/react/cjs/react.development.js:1507:20)
      at App (/Users/USER_DIRECTORY/experimental/npm-workspaces/packages/package-b/src/components/App.tsx:10:29)
      at renderWithHooks (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:14985:18)
      at mountIndeterminateComponent (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:17811:13)
      at beginWork (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:19049:16)
      at HTMLUnknownElement.callCallback (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:3945:14)
      at HTMLUnknownElement.callTheUserObjectsOperation (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)
      at innerInvokeEventListeners (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25)
      at invokeEventListeners (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
      at HTMLUnknownElementImpl._dispatch (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
      at HTMLUnknownElementImpl.dispatchEvent (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
      at HTMLUnknownElement.dispatchEvent (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34)
      at Object.invokeGuardedCallbackDev (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:3994:16)
      at invokeGuardedCallback (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:4056:31)
      at beginWork$1 (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:23964:7)
      at performUnitOfWork (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:22779:12)
      at workLoopSync (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:22707:5)
      at renderRootSync (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:22670:7)
      at performSyncWorkOnRoot (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:22293:18)
      at scheduleUpdateOnFiber (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:21881:7)
      at updateContainer (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:25482:3)
      at /Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:26021:7
      at unbatchedUpdates (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:22431:12)
      at legacyRenderSubtreeIntoContainer (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:26020:5)
      at Object.render (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:26103:10)
      at /Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/@testing-library/react/dist/pure.js:99:25
      at batchedUpdates$1 (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom.development.js:22380:12)
      at act (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/react-dom/cjs/react-dom-test-utils.development.js:1042:14)
      at Object.render (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/@testing-library/react/dist/pure.js:95:26)
      at Object.<anonymous> (/Users/USER_DIRECTORY/experimental/npm-workspaces/packages/package-b/tests/components/App.test.tsx:5:29)
      at Object.asyncJestTest (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
      at /Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jest-jasmine2/build/queueRunner.js:45:12
      at new Promise (<anonymous>)
      at mapper (/Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
      at /Users/USER_DIRECTORY/experimental/npm-workspaces/node_modules/jest-jasmine2/build/queueRunner.js:75:41
      at processTicksAndRejections (internal/process/task_queues.js:93:5)

  at VirtualConsole.<anonymous> (../../node_modules/jsdom/lib/jsdom/virtual-console.js:29:45)
  at reportException (../../node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:28)
  at innerInvokeEventListeners (../../node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:341:9)
  at invokeEventListeners (../../node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
  at HTMLUnknownElementImpl._dispatch (../../node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
  at HTMLUnknownElementImpl.dispatchEvent (../../node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
  at HTMLUnknownElement.dispatchEvent (../../node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34)

console.error
  The above error occurred in the <App> component:
  
      at App (/Users/USER_DIRECTORY/experimental/npm-workspaces/packages/package-b/src/components/App.tsx:10:29)
  
  Consider adding an error boundary to your tree to customize error handling behavior.
  Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.

  at logCapturedError (../../node_modules/react-dom/cjs/react-dom.development.js:20085:23)
  at update.callback (../../node_modules/react-dom/cjs/react-dom.development.js:20118:5)
  at callCallback (../../node_modules/react-dom/cjs/react-dom.development.js:12318:12)
  at commitUpdateQueue (../../node_modules/react-dom/cjs/react-dom.development.js:12339:9)
  at commitLifeCycles (../../node_modules/react-dom/cjs/react-dom.development.js:20736:11)
  at commitLayoutEffects (../../node_modules/react-dom/cjs/react-dom.development.js:23426:7)
  at HTMLUnknownElement.callCallback (../../node_modules/react-dom/cjs/react-dom.development.js:3945:14)
  at HTMLUnknownElement.callTheUserObjectsOperation (../../node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)

● Testing render

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

   8 | export const App = (props: AppProps): JSX.Element => {
   9 |   // Create the count state.
> 10 |   const [count, setCount] = useState(0);
     |                             ^
  11 |   const [user, setUser] = useState<string>();
  12 |
  13 |   // Create the counter (+1 every second).

  at resolveDispatcher (node_modules/react/cjs/react.development.js:1476:13)
  at Object.useState (node_modules/react/cjs/react.development.js:1507:20)
  at App (src/components/App.tsx:10:29)
  at renderWithHooks (../../node_modules/react-dom/cjs/react-dom.development.js:14985:18)
  at mountIndeterminateComponent (../../node_modules/react-dom/cjs/react-dom.development.js:17811:13)
  at beginWork (../../node_modules/react-dom/cjs/react-dom.development.js:19049:16)
  at HTMLUnknownElement.callCallback (../../node_modules/react-dom/cjs/react-dom.development.js:3945:14)
  at HTMLUnknownElement.callTheUserObjectsOperation (../../node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)
  at innerInvokeEventListeners (../../node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25)
  at invokeEventListeners (../../node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
  at HTMLUnknownElementImpl._dispatch (../../node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
  at HTMLUnknownElementImpl.dispatchEvent (../../node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
  at HTMLUnknownElement.dispatchEvent (../../node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34)
  at Object.invokeGuardedCallbackDev (../../node_modules/react-dom/cjs/react-dom.development.js:3994:16)
  at invokeGuardedCallback (../../node_modules/react-dom/cjs/react-dom.development.js:4056:31)
  at beginWork$1 (../../node_modules/react-dom/cjs/react-dom.development.js:23964:7)
  at performUnitOfWork (../../node_modules/react-dom/cjs/react-dom.development.js:22779:12)
  at workLoopSync (../../node_modules/react-dom/cjs/react-dom.development.js:22707:5)
  at renderRootSync (../../node_modules/react-dom/cjs/react-dom.development.js:22670:7)
  at performSyncWorkOnRoot (../../node_modules/react-dom/cjs/react-dom.development.js:22293:18)
  at scheduleUpdateOnFiber (../../node_modules/react-dom/cjs/react-dom.development.js:21881:7)
  at updateContainer (../../node_modules/react-dom/cjs/react-dom.development.js:25482:3)
  at ../../node_modules/react-dom/cjs/react-dom.development.js:26021:7
  at unbatchedUpdates (../../node_modules/react-dom/cjs/react-dom.development.js:22431:12)
  at legacyRenderSubtreeIntoContainer (../../node_modules/react-dom/cjs/react-dom.development.js:26020:5)
  at Object.render (../../node_modules/react-dom/cjs/react-dom.development.js:26103:10)
  at ../../node_modules/@testing-library/react/dist/pure.js:99:25
  at batchedUpdates$1 (../../node_modules/react-dom/cjs/react-dom.development.js:22380:12)
  at act (../../node_modules/react-dom/cjs/react-dom-test-utils.development.js:1042:14)
  at Object.render (../../node_modules/@testing-library/react/dist/pure.js:95:26)
  at Object.<anonymous> (tests/components/App.test.tsx:5:29)

So the @testing-library/react packages seems to be referencing the root level React versions, which cause an issue with the local versions.

Expected Behavior:

I expected the @testing-library/react to reference the workspace specific React versions.

Steps To Reproduce:

Package A package.json:
"dependencies": {
"react": "17.0.2",
"react-dom": "17.0.2",
},
"devDependencies": {
"@testing-library/react": "11.2.5",
"react-test-renderer": "17.0.2",
}

Package B package.json
"dependencies": {
"react": "17.0.1",
"react-dom": "17.0.1",
},
"devDependencies": {
"@testing-library/react": "11.2.5",
"react-test-renderer": "17.0.1",
}

And I created a very simple test for each package:

import { render } from '@testing-library/react';
import { App } from '../../src/components/App';

test('Testing render', () => {
const renderedElement = render();

expect(renderedElement).toBeDefined();

});

Environment:

OS: MacOS 11.2.3
Node: 14.15.4
npm: 7.7.5

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the failure with Jest in package-b and compare it with package-a, using packages/package-b/tests/components/App.test.tsx and packages/package-b/src/components/App.tsx. Trace which React and React DOM copies the test and @testing-library/react resolve. Done means package-b's test passes with its local React versions while the workspace's peer dependencies resolve correctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, nodejs, react, typescript
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.