Preact: Replacing import { h } with React doesn't work in jest tests

Created on 13 Dec 2019  ·  9Comments  ·  Source: preactjs/preact

Steps to reproduce:

  1. $ preact create default preact (preact-cli v2.2.1)
    cd ./preact
  2. npm i -D @babel/plugin-transform-react-jsx
  3. Update package.json
"jest": {
    ...
    "moduleNameMapper": {
      "react": "preact/compat",
      "react-dom/test-utils": "preact/test-utils",
      "react-dom": "preact/compat"
    }
  }
  1. in header.test.js replace import { h } from 'preact' with
    import React from 'react'
  2. in .babelrc add
plugins: [
        ['@babel/plugin-transform-react-jsx', {
          "pragma": "h",
          "pragmaFrag": "Fragment"
        }]
      ]

FAIL tests/header.test.js
● Test suite failed to run

TypeError: Cannot read property 'prototype' of undefined

  3 | 
  4 | configure({
> 5 |   adapter: new Adapter()
    |                                                       ^
  6 | });
  7 | 

  at node_modules/preact/compat/dist/compat.js:1:469
  at Object.<anonymous> (node_modules/preact/compat/dist/compat.js:1:611)
  at Object.<anonymous> (tests/__mocks__/setupTests.js:5:55)

Most helpful comment

Changing moduleNameMapper key to regexp form will fix this issue (At least in my case).

  moduleNameMapper: {
    "^react$": "preact/compat",
    "^react-dom$": "preact/compat",
    "^react-dom/test-utils$": "preact/test-utils",
  },

background:

I ran a jest test with the Chrome Remote Debugger and found that require ('preact') in preact/compat only returned a empty object({}). Then preact/compat try to extend require('preact').Component, but it's undefined in this situation.

All 9 comments

This is a misconfiguration of the babel plugins. By default @babel/plugin-transform-react-jsx will use React.createElement as the jsx constructor function. If you manually change that to h, but don't import the function anywhere, than this will break. If you want to use import React from 'react' instead, you need to change the pragma settings accordingly.

plugins: [
  ['@babel/plugin-transform-react-jsx', {
    "pragma": "React.createElement",
    "pragmaFrag": "React.Fragment"
  }]
]

I'll add that by default @babel/plugin-transform-react-jsx will use React.createElement and React.Fragment, therefore in your .babelrc you may just write:

plugins: ["@babel/plugin-transform-react-jsx"]

@marvinhagemeister I can actually reproduce the issue; I am not sure if this is from Preact, Preact CLI or Jest though.

Alright, reopening

I think the issue is the following:

For Preact-cli we use babel-jest and our own createConfig here when we go look at that config we see that babelrc: false which means we aren't allowing any custom overrides from your babelrc. By default we're using https://github.com/preactjs/preact-cli/blob/master/packages/cli/lib/lib/babel-config.js#L34 making it use the wrong default .

I wonder if flipping babelrc to true would introduce other issues.

/CC @ForsakenHarmony @prateekbh

@JoviDeCroock I also have a project without preact-cli and there on npm test the error is:

TypeError: Cannot read property 'prototype' of undefined
      at node_modules/preact/compat/src/PureComponent.js:11:31
      at Object.comparer (node_modules/preact/compat/src/memo.js:11:25)

It might be misconfiguration, but also can be related to the same issue.

Changing moduleNameMapper key to regexp form will fix this issue (At least in my case).

  moduleNameMapper: {
    "^react$": "preact/compat",
    "^react-dom$": "preact/compat",
    "^react-dom/test-utils$": "preact/test-utils",
  },

background:

I ran a jest test with the Chrome Remote Debugger and found that require ('preact') in preact/compat only returned a empty object({}). Then preact/compat try to extend require('preact').Component, but it's undefined in this situation.

@ka2n Had the same issue than mentionned by @ssuvorov and it worked for me as well! 🙏

guys, if you have your custom configuration file, could you check the next, please:

"moduleNameMapper": {
-      "config": "<rootDir>/src/configuration/config.development.js",
+      "^config": "<rootDir>/src/configuration/config.development.js",
     ...
}

After I changed that, it works for me

Was this page helpful?
0 / 5 - 0 ratings