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

React Native自定义Text组件单元测试报错:需HTMLElement/SVGElement

React Native(Expo)NativeWind封装Text组件的单元测试问题

问题描述

作为React Native(Expo)和单元测试新手,我在测试基于NativeWind封装的自定义Text组件样式时遇到问题:使用toHaveStyle断言字体大小时,报错提示接收值必须是HTMLElement或SVGElement,但实际拿到的是React Fiber对象,即便引入@testing-library/jest-native扩展也无法解决。

自定义组件代码

import { styled } from 'nativewind';
import React from 'react';
import type { TextProps } from 'react-native';
import { StyleSheet, Text as NNText } from 'react-native';

const SText = styled(NNText);

export interface CustomTextProps extends TextProps {
  variant?: keyof typeof textVariants;
  className?: string;
}

export const textVariants = {
//.....
};

export const Text = ({
  variant = 'md',
  className = '',
  style,
  children,
  ...props
}: CustomTextProps) => {
  return (
    <SText
      className={`
      ${textVariants[variant]}
      ${className}
    `}
      style={StyleSheet.flatten([
        { writingDirection: isRTL ? 'rtl' : 'ltr' },
        style,
      ])}
      {...props}
    >
      {children}
    </SText>
  );
};

测试代码

import '@testing-library/jest-native/extend-expect';
import { render, screen } from '@testing-library/react-native';

import { CustomTextProps, Text } from '../text';

describe('text component', () => {
  const renderComponent = (props: CustomTextProps) =>
    render(<Text {...props} />);

  it('should accept variant and className props', async () => {
    renderComponent({
      variant: 'xs',
      className: 'bg-primary-50',
      children: 'tested text',
    });

    const text = screen.getByText('tested text');
    expect(text).toBeTruthy();

    expect(text).toHaveStyle({ fontSize: 16 }); // 报错位置
  });
});

报错信息

expect(received).toHaveStyle()

received value must be an HTMLElement or an SVGElement.
Received has type:  object
Received has value: {"_fiber": {"_debugHookTypes": null, "_debugNeedsRemount": false, "_debugOwner": [FiberNode], "_debugSource": null, "actualDuration": 0, "actualStartTime": -1, "alternate": null, "child": [FiberNode], "childLanes": 0, "deletions": null, "dependencies": null, "elementType": [Function Component], "flags": 1, "index": 0, "key": null, "lanes": 0, "memoizedProps": [Object], "memoizedState": null, "mode": 0, "pendingProps": [Object], "ref": null, "return": [FiberNode], "selfBaseDuration": 0, "sibling": null, "stateNode": [Component], "subtreeFlags": 0, "tag": 1, "treeBaseDuration": 0, "type": [Function Component], "updateQueue": [Object]}}

  18 |     expect(text).toBeTruthy();
  19 |
> 20 |     expect(text).toHaveStyle({ fontSize: 16 });
     |                  ^
  21 |   });
  22 | });
  23 |

  at __EXTERNAL_MATCHER_TRAP__ (node_modules/expect/build/index.js:342:30)
  at Object.toHaveStyle (node_modules/expect/build/index.js:343:15)
  at Object.<anonymous> (src/ui/core/__test__/text.test.tsx:20:18)
  at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
  at _next (node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
  at node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
  at tryCallTwo (node_modules/promise/lib/core.js:45:5)
  at doResolve (node_modules/promise/lib/core.js:200:13)
  at new Promise (node_modules/promise/lib/core.js:66:3)

解决方案

1. 配置NativeWind Jest预设

NativeWind需要在测试环境中配置专门的预设来解析Tailwind样式,在jest.config.js中添加:

module.exports = {
  preset: 'nativewind/jest',
  // 保留你现有的其他Jest配置
};

2. 确保使用RN测试库的匹配器

@testing-library/jest-native的toHaveStyle是为RN组件设计的,但需要确保测试对象是RN组件实例。可以给组件添加testID来精准获取:
修改测试代码:

import '@testing-library/jest-native/extend-expect';
import { render, screen } from '@testing-library/react-native';

import { CustomTextProps, Text } from '../text';

describe('text component', () => {
  const renderComponent = (props: CustomTextProps) =>
    render(<Text {...props} />);

  it('should apply correct styles for variant', async () => {
    renderComponent({
      variant: 'xs',
      className: 'bg-primary-50',
      children: 'tested text',
      testID: 'custom-text-component' // 添加testID
    });

    const textComponent = screen.getByTestId('custom-text-component');
    expect(textComponent).toBeTruthy();

    // 使用jest-native的toHaveStyle断言
    expect(textComponent).toHaveStyle({ fontSize: 16 });
  });
});

3. 备选:直接断言组件样式属性

如果toHaveStyle仍不生效,可以直接检查组件的props.style,或者验证是否应用了正确的variant类:

// 方式1:断言style属性
expect(textComponent.props.style).toContainEqual({ fontSize: 16 });

// 方式2:验证className是否包含对应variant的样式类
import { textVariants } from '../text';
expect(textComponent.props.className).toContain(textVariants.xs);

4. 检查版本兼容性

确保@testing-library/react-native、@testing-library/jest-native和nativewind版本互相兼容,比如NativeWind v4需要搭配较新的测试库版本,建议参考官方文档确认版本匹配。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 21:25:22