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

React Native组件测试Jest语法错误求助:TouchableOpacity解析失败

React Native TypeScript Jest组件测试语法错误修复

问题概述

TypeScript React Native应用中,单元测试可正常执行,但编写TouchableOpacity组件测试时,Jest抛出SyntaxError,提示react-native库中TouchableOpacity.js文件存在未初始化的const声明。已配置Babel转换规则和transformIgnorePatterns,但仍无法完成文件转换,导致测试失败。

相关代码与配置

测试文件

// ButtonComponent.test.js
import React from 'react';
import {render, fireEvent} from '@testing-library/react-native';
import {TouchableOpacity, Text} from 'react-native';

describe('ButtonComponent', () => {
  it('calls onPress when pressed', () => {
    const mockOnPress = jest.fn();

    const {getByText} = render(
      <TouchableOpacity onPress={mockOnPress}>
        <Text>Click Me</Text>
      </TouchableOpacity>,
    );

    fireEvent.press(getByText('Click Me'));
    expect(mockOnPress).toHaveBeenCalled();
  });
});

Babel配置

module.exports = {
  presets: [
    'module:metro-react-native-babel-preset',
    '@babel/preset-react',
    '@babel/preset-typescript',
    '@babel/preset-env',
  ],
  plugins: [
    [
      'module-resolver',
      {
        alias: {
          '@': './src',
        },
      },
    ],
    [
      'module:react-native-dotenv',
      {
        moduleName: '@env',
        path: '.env',
      },
    ],
  ],
};

Jest配置

module.exports = {
  preset: 'react-native',
  transform: {
    '^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
  },
  moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'],
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
      '<rootDir>/__mocks__/fileMock.js',
    '^@env$': '<rootDir>/src/types/env.d.ts',
  },
  transformIgnorePatterns: [
    'node_modules/(?!(react-native|@react-native|@react-native(-community)|react-native-gesture-handler|react-native-reanimated|@react-navigation)/)',
  ],
  testPathIgnorePatterns: ['/node_modules/', '/dist/'],
  testEnvironment: 'node',
  collectCoverage: true,
  coverageReporters: ['json', 'lcov', 'text', 'clover'],
  verbose: true,
};

TypeScript配置

{
  "extends": "@react-native/typescript-config/tsconfig.json",
  "compilerOptions": {
    "jsx": "react-native",
    "allowJs": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    },
    "allowSyntheticDefaultImports": true,
    "strict": true,  
    "esModuleInterop": true,  
    "resolveJsonModule": true  
  },
  "typeRoots": ["./src/types", "./node_modules/@types"],
  "include": ["src/**/*", "./App.tsx", "__tests__"]
}

package.json

{
  "name": "zero",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "lint": "eslint .",
    "start": "react-native start",
    "test": "jest .",
    "test:watch": "jest --watch",
    "test:coverage": "jest --collectCoverage --coverageDirectory=\"./coverage\"",
    "commit": "cz",
    "prepare": "husky",
    "pretty": "prettier --write ."
  },
  "dependencies": {
    "@babel/core": "^7.26.7",
    "@babel/runtime": "^7.26.7",
    "@react-navigation/bottom-tabs": "^7.2.0",
    "@react-navigation/native": "^7.0.14",
    "@react-navigation/native-stack": "^7.2.0",
    "@reduxjs/toolkit": "^2.5.1",
    "axios": "^1.7.9",
    "axios-mock-adapter": "^2.1.0",
    "react": "18.3.1",
    "react-native": "^0.77.0",
    "react-native-error-boundary": "^1.2.7",
    "react-native-fast-image": "^8.6.3",
    "react-native-gesture-handler": "^2.22.1",
    "react-native-keychain": "^9.2.2",
    "react-native-reanimated": "^3.16.7",
    "react-native-safe-area-context": "^5.1.0",
    "react-native-screens": "^4.6.0",
    "react-native-splash-screen": "^3.3.0",
    "react-native-toast-message": "^2.2.1",
    "react-native-vector-icons": "^10.2.0",
    "react-redux": "^9.2.0"
  },
  "devDependencies": {
    "@babel/plugin-transform-react-jsx": "^7.25.9",
    "@babel/preset-env": "^7.26.7",
    "@babel/preset-react": "^7.26.3",
    "@babel/preset-typescript": "^7.26.0",
    "@react-native-community/cli": "15.0.1",
    "@react-native-community/cli-platform-android": "15.0.1",
    "@react-native-community/cli-platform-ios": "15.0.1",
    "@react-native/babel-preset": "^0.77.0",
    "@react-native/eslint-config": "^0.77.0",
    "@react-native/metro-config": "^0.77.0",
    "@react-native/typescript-config": "^0.77.0",
    "@testing-library/react-native": "^12.9.0",
    "@types/jest": "^29.5.14",
    "@types/react": "^18.3.18",
    "@types/react-native": "^0.72.8",
    "@types/react-native-dotenv": "^0.2.2",
    "@types/react-native-vector-icons": "^6.4.18",
    "@types/react-test-renderer": "^18.0.0",
    "babel-jest": "^29.7.0",
    "babel-plugin-module-resolver": "^5.0.2",
    "commitizen": "^4.3.1",
    "cz-conventional-changelog": "^3.3.0",
    "eslint": "^8.19.0",
    "eslint-plugin-testing-library": "^7.1.1",
    "husky": "^9.1.7",
    "jest": "^29.7.0",
    "jest-react-native": "^18.0.0",
    "metro-react-native-babel-preset": "^0.77.0",
    "prettier": "2.8.8",
    "react-native-dotenv": "^3.4.11",
    "react-test-renderer": "^18.2.0",
    "ts-jest": "^29.2.5",
    "typescript": "5.0.4"
  },
  "engines": {
    "node": ">=18"
  },
  "config": {
    "commitizen": {
      "path": "./node_modules/cz-conventional-changelog"
    }
  }
}

修复步骤

1. 调整Jest测试环境

将testEnvironment从node改为jsdom,React Native组件测试需要DOM环境支持:

// jest.config.js
module.exports = {
  // ...其他配置
  testEnvironment: 'jsdom',
}

也可直接移除该配置,使用react-native预设的默认测试环境。

2. 简化Babel预设

metro-react-native-babel-preset已包含React和环境转换逻辑,移除冗余预设,仅保留TypeScript预设:

// babel.config.js
module.exports = {
  presets: [
    'module:metro-react-native-babel-preset',
    '@babel/preset-typescript',
  ],
  plugins: [
    [
      'module-resolver',
      {
        alias: {
          '@': './src',
        },
      },
    ],
    [
      'module:react-native-dotenv',
      {
        moduleName: '@env',
        path: '.env',
      },
    ],
  ],
};

3. 优化transformIgnorePatterns正则

确保react-native内部所有模块都被正确转换,修正正则表达式:

// jest.config.js
module.exports = {
  // ...其他配置
  transformIgnorePatterns: [
    'node_modules/(?!((react-native|@react-native(-community)?)|react-native-gesture-handler|react-native-reanimated|@react-navigation)/)',
  ],
}

4. 删除过时依赖

移除devDependencies中的jest-react-native,该依赖与react-native预设冲突:

// package.json
"devDependencies": {
  // 移除 "jest-react-native": "^18.0.0"
}

5. 统一测试文件后缀

将测试文件ButtonComponent.test.js重命名为ButtonComponent.test.tsx,匹配TypeScript项目规范,确保Babel正确识别并转换。

完成上述修改后,重新运行组件测试即可解决语法错误,模拟按钮点击的测试逻辑将正常执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 13:58:09