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

使用Jest测试twin.macro样式的React组件时出现tw未定义错误

解决Vite+React+TypeScript环境下twin.macro tw.div 测试报错“Cannot read properties of undefined (reading 'div')”

问题场景

使用Vite+React+TypeScript+Tailwind+twin.macro技术栈开发组件时,用tw.div``语法定义样式组件,运行测试时出现错误:Cannot read properties of undefined (reading 'div')`。

组件代码示例:

// MyCustomComponent.tsx
import tw from 'twin.macro';

const Container = tw.div`relative w-full`;

export const MyCustomComponent = () => {
  return (
    <Container>
      ...
    </Container>
  )
}

测试代码示例:

// MyCustomComponent.test.tsx
import React from 'react';
import { render } from '@testing-library/react';
import { MyCustomComponent } from '../MyCustomComponent';

describe('MyCustomComponent...', () => {
  it('should render', () => {
    render(<MyCustomComponent />);
    ...
  });
});

可行解决方案

方案1:配置Babel处理twin.macro宏

测试环境(如Jest)默认不会处理twin.macro的宏语法,需要通过Babel插件转换:

  1. 安装必要依赖:
npm install --save-dev babel-plugin-twin @babel/preset-react @babel/preset-typescript babel-jest
  1. 创建项目根目录的babel.config.js:
module.exports = {
  presets: [
    '@babel/preset-react',
    '@babel/preset-typescript',
  ],
  plugins: ['babel-plugin-twin'],
};
  1. 更新Jest配置(jest.config.js),指定用babel-jest处理TS/TSX文件:
module.exports = {
  transform: {
    '^.+\\.(ts|tsx)$': 'babel-jest',
  },
};

方案2:Mock twin.macro(快速临时解决)

如果不想配置Babel,直接在测试文件中mock tw对象,让测试环境识别tw.div这类语法:

在测试文件顶部添加mock代码:

import tw from 'twin.macro';

jest.mock('twin.macro', () => ({
  __esModule: true,
  default: new Proxy({}, {
    get(_, tagName) {
      // 返回一个生成对应标签的组件,保留className属性
      return (className) => (props) => {
        const Component = tagName;
        return <Component className={className} {...props} />;
      };
    },
  }),
}));

说明

部分针对Webpack环境的解决方案可能不适用于Vite,因为两者的构建/测试配置逻辑不同,上述方案适配Vite+Jest的测试场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 23:45:54