You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

打包不含React的React组件库时Jest测试遇ReferenceError求助

解决React组件库Jest测试错误&更优构建方案建议

嘿,我来帮你拆解下遇到的问题,再分享些组件库开发的实用思路~

一、先搞定ReferenceError: React is not defined的问题

这个错误的核心原因是:JSX转译后本质是调用React.createElement,但你的组件库没打包React,测试环境里也没提供全局的React,同时组件里没手动导入React,就会触发这个报错。给你两个靠谱的解决办法:

方案1:让Babel自动处理React导入(推荐,适配React 17+)

从React 17开始,官方支持JSX自动导入,不需要在每个组件里写import React from 'react'。你只需要在Babel配置里修改@babel/plugin-transform-react-jsx的runtime设置:

// .babelrc 或者 babel.config.json
{
  "presets": [
    // 你的其他preset,比如@babel/preset-react
  ],
  "plugins": [
    ["@babel/plugin-transform-react-jsx", {
      "runtime": "automatic"
    }]
  ]
}

这样Babel会自动帮你导入JSX需要的React相关函数,不管是组件代码还是测试代码,都不用手动加React的import了,从根源解决未定义问题。

方案2:在Jest全局配置里注入React(适配React 16及以下)

如果你还在用React 16或更早版本,或者不想改Babel配置,可以在Jest的setup文件里把React挂到全局对象上:

// jest.setup.js
import React from 'react';
// 全局挂载React,让测试环境里的JSX能找到它
global.React = React;

// 你的enzyme原有配置
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
configure({ adapter: new Adapter() })

二、解决测试断言的对比问题

你之前遇到的预期<form />,实际收到ShallowWrapper {}错误,是因为enzyme的shallow()返回的是一个Wrapper对象,不是原生的React元素,不能直接用toEqual和<form />对比。正确的做法有两种:

方法1:用快照测试(你已经尝试的方案,完善下)

配合enzyme-to-json把Wrapper转成可序列化的对象,再用快照断言:

import React from 'react'
import { shallow } from 'enzyme'
import { Form } from './form.js'
import toJson from 'enzyme-to-json'

describe('Test forms', () => {
  test('render correctly', () => {
    const wrapper = shallow(<Form />);
    // 生成/对比快照
    expect(toJson(wrapper)).toMatchSnapshot();
  })
})

方法2:直接断言Wrapper的属性/结构

如果不想用快照,也可以直接断言Wrapper的类型:

test('render correctly', () => {
  const wrapper = shallow(<Form />);
  // 断言渲染的是form元素
  expect(wrapper.is('form')).toBe(true);
})

三、React组件库的更优构建方案

手动配置Webpack+Babel确实有点繁琐,现在有很多更省心的工具可以替代,推荐几个主流选项:

  • Vite + Vitest:
    Vite是当下最火的构建工具,针对库开发有专门的build.lib配置,默认支持React,打包速度极快。测试可以用Vitest(和Jest语法兼容,但执行速度更快),配置几乎零成本。只需要在vite.config.js里简单设置:

    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'
    
    export default defineConfig({
      plugins: [react()],
      build: {
        lib: {
          entry: 'src/index.js',
          name: 'YourComponentLib',
          fileName: (format) => `your-lib.${format}.js`
        },
        rollupOptions: {
          // 把React设为外部依赖,不打包进库
          external: ['react', 'react-dom'],
          output: {
            // 为外部依赖提供全局变量(如果用户用UMD格式)
            globals: {
              react: 'React',
              'react-dom': 'ReactDOM'
            }
          }
        }
      }
    })
    
  • Rollup:
    Rollup是专为库打包设计的工具,比Webpack更轻量,能生成更干净的代码。配合@rollup/plugin-babel、@rollup/plugin-node-resolve等插件,很容易产出ES/CJS等多种格式的包,支持按需加载。

  • Storybook:
    不管用哪种构建工具,都建议搭配Storybook,它能帮你快速搭建组件的预览、文档环境,方便开发和测试组件的各种状态,是组件库开发的标配工具。

另外,别忘了把React、React-dom设为peerDependencies,在package.json里配置:

{
  "peerDependencies": {
    "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
    "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
  }
}

这样用户安装你的库时,会复用自己项目里的React版本,避免重复引入,和你最初的思路一致~

内容的提问来源于stack exchange,提问作者Dillan Wilding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:14:48