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

Using urql's useMutation hook inside tests yields "TypeError: Cannot read properties of undefined (reading '__H')" error possibly because of currentComponent in getHookState is undefined #3468

Closed
EmreErdogan opened this issue Mar 1, 2022 · 6 comments

Comments

@EmreErdogan
Copy link

EmreErdogan commented Mar 1, 2022

Describe the bug
I'm getting TypeError: Cannot read properties of undefined (reading '__H') error on test environment when rendering a component which uses urql's useMutation hook. The component renders without a problem on browser.

Project structure
@preact/preset-vite + @urql/preact + vitest + @testing-library/preact

About the hook

Link to source code of useMutation.

Please see the source code of the hook, it looks fine imho. I don't see any problem with its implementation.

As far as I could debug the problem and dug into the source code of Preact hooks, I saw that this line yields the error.

currentComponent.__hooks ||

Because, at the time of calling getHookState function, currentComponent variable is undefined. So, trying to access currentComponent.__hooks fails.

Error output

 FAIL  src/Home.test.tsx > Home > should render Home
TypeError: Cannot read properties of undefined (reading '__H')
 ❯ m file:/Users/emrebaba/sandbox/preact/vite-preact-test/node_modules/preact/hooks/dist/hooks.mjs:1:151
 ❯ d file:/Users/emrebaba/sandbox/preact/vite-preact-test/node_modules/preact/hooks/dist/hooks.mjs:1:792
 ❯ s file:/Users/emrebaba/sandbox/preact/vite-preact-test/node_modules/preact/hooks/dist/hooks.mjs:1:628
 ❯ Module.useMutation file:/Users/emrebaba/sandbox/preact/vite-preact-test/node_modules/@urql/preact/dist/urql-preact.mjs:225:11
 ❯ d.Home [as constructor] src/Home.tsx:14:27
     12|
     13| export const Home = () => {
     14|   const [result, mutate] = useMutation(mutation);
       |                           ^
     15|
     16|   return 
Hello world!
; ❯ d.M [as render] node_modules/preact/dist/preact.js:1:7851 ❯ I node_modules/preact/dist/preact.js:1:5598 ❯ m node_modules/preact/dist/preact.js:1:2096 ❯ I node_modules/preact/dist/preact.js:1:5831 ❯ m node_modules/preact/dist/preact.js:1:2096 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ Test Files 1 failed (1) Tests 1 failed | 1 passed (2) Time 2.18s (in thread 6ms, 39248.40%)

To Reproduce
I created a simple repository to show the issue => https://github.com/EmreErdogan/vite-preact-test

Steps to reproduce the behavior:

  1. Clone the repository (sorry, couldn't make the tests play nice with CodeSandbox/Stackblitz environments)
  2. cd into it and run npm install
  3. run npm run test

Expected behavior
Test should succeed.

@EmreErdogan EmreErdogan changed the title Using urql's useMutation hook inside tests yields TypeError: Cannot read properties of undefined (reading '__H') error possibly because of currentComponent in getHookState is undefined Using urql's useMutation hook inside tests yields "TypeError: Cannot read properties of undefined (reading '__H')" error possibly because of currentComponent in getHookState is undefined Mar 1, 2022
@JoviDeCroock
Copy link
Member

JoviDeCroock commented Mar 4, 2022

This isn't really a Preact issue, to make this work you would need to add something like this to the vite-config I assume

  optimizeDeps: {
    include: ['preact/hooks', 'preact/compat', 'preact']
  },

This because we see a duplicate entry of preact in the bundle atm CC @marvinhagemeister should we also mirror this in the vite-preset. We use this trick in the prefresh-tests as well

@EmreErdogan
Copy link
Author

Hi @JoviDeCroock Thanks for your attention!

I tried your suggestion

  optimizeDeps: {
    include: ['preact/hooks', 'preact/compat', 'preact']
  },

but I got the same error. As a side note I've managed to make the same setup work withreact instead of preact without any problem. But I'd definitely stick with preact if I could find a solution for this issue.

Thanks again 😊

@JoviDeCroock
Copy link
Member

JoviDeCroock commented Mar 4, 2022

I tried that solution with your reproduction and it worked perfectly 😅 oh nvm, it only happens in test? we might need something similar for vitest let me explore

@EmreErdogan
Copy link
Author

Really appreciate that. I'd happily contribute to this if you direct me to the correct path 😬

@RapidOwl
Copy link

RapidOwl commented Sep 8, 2022

@EmreErdogan I just ran into this issue with Preact + Vitest and found this solution on a similar issue on the Vitest repo: vitest-dev/vitest#1652 (comment). Forcing the aliased module to load using require fixed it for me.

Stuck this at the top of my vite.config.js:

import { createRequire } from 'module';

const require = createRequire(import.meta.url);

Then I've got a resolve section in the object I pass to defineConfig.

resolve: {
	alias: [
		{
			find: 'preact/hooks',
			replacement: require.resolve('preact/hooks')
		}
	]
}

This is apparently due to the way Vite imports unprocessed modules. I don't really understand the CJS vs ESM madness and wish it wasn't a thing.

Weirdly, I only had this problem with preact/hooks. htm/preact worked fine without require.

@nakaakist
Copy link

nakaakist commented Sep 20, 2023

In a project that aliases react to preact using preact/compat, I had to slightly modify @RapidOwl 's solution.

At the top of vite.config.js:

import { createRequire } from 'module';

const require = createRequire(import.meta.url);

Then, add the following inside the defineConfig:

resolve: {
  alias: [
    {
      find: 'react',
      replacement: require.resolve('preact/compat'),
    },
    // below is the same as https://preactjs.com/guide/v10/getting-started#aliasing-react-to-preact
    { find: 'react-dom/test-utils', replacement: 'preact/test-utils' },
    { find: 'react-dom', replacement: 'preact/compat' },
    { find: 'react/jsx-runtime', replacement: 'preact/jsx-runtime' },
  ],
}

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

4 participants