as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
Ring
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持

步骤6: 测试更新

步骤6: 测试更新

6.1 更新jest.config.js

transformIgnorePatterns须包含@amazon-devices/react-native-kepler。程序包4.0.0会在its jest/setup.js文件中使用ES模块语法。如果不采用此模式,Jest文件会报错SyntaxError: 无法在模块外使用导入语句

module.exports = {
  preset: 'react-native',
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  transformIgnorePatterns: [
    'node_modules/(?!((jest-)?react-native|@react-native(-community)?|@amazon-devices/react-native-kepler)|react-native-safe-area-context)',
  ],
};

6.2 为电视模拟创建jest.setup.js

RN 0.83更改了模拟在测试环境中的工作方式。创建一个包含TV适用模拟的设置文件,如下例所示。

// jest.setup.js

/**
 * 为电视平台模拟Dimensions API
 * Fire TV设备的分辨率达到1920x1080(全高清),比例系数为1
 */
jest.mock('react-native/Libraries/Utilities/Dimensions', () => ({
  get: jest.fn().mockReturnValue({
    width: 1920,
    height: 1080,
    scale: 1,
    fontScale: 1,
  }),
  addEventListener: jest.fn(),
  removeEventListener: jest.fn(),
}));

/**
 * 为电视平台模拟PixelRatio API
 * 电视设备使用的比例系数为1(无像素倍增)
 */
jest.mock('react-native/Libraries/Utilities/PixelRatio', () => ({
  default: {
    get: jest.fn().mockReturnValue(1),
    getFontScale: jest.fn().mockReturnValue(1),
    getPixelSizeForLayoutSize: jest.fn((layoutSize) => layoutSize),
    roundToNearestPixel: jest.fn((layoutSize) => layoutSize),
  },
}));

/**
 * 模拟NativeAnimatedModule — RN 0.83会调用23种特定方法。
 * 任何触发导航动画的测试均为必填项。
 */
jest.mock('react-native/Libraries/Animated/NativeAnimatedModule', () => ({
  __esModule: true,
  default: {
    startOperationBatch: jest.fn(),
    finishOperationBatch: jest.fn(),
    createAnimatedNode: jest.fn(),
    updateAnimatedNodeConfig: jest.fn(),
    getValue: jest.fn(),
    startListeningToAnimatedNodeValue: jest.fn(),
    stopListeningToAnimatedNodeValue: jest.fn(),
    connectAnimatedNodes: jest.fn(),
    disconnectAnimatedNodes: jest.fn(),
    startAnimatingNode: jest.fn(),
    stopAnimation: jest.fn(),
    setAnimatedNodeValue: jest.fn(),
    setAnimatedNodeOffset: jest.fn(),
    flattenAnimatedNodeOffset: jest.fn(),
    extractAnimatedNodeOffset: jest.fn(),
    connectAnimatedNodeToView: jest.fn(),
    disconnectAnimatedNodeFromView: jest.fn(),
    restoreDefaultValues: jest.fn(),
    dropAnimatedNode: jest.fn(),
    addAnimatedEventToView: jest.fn(),
    removeAnimatedEventFromView: jest.fn(),
    addListener: jest.fn(),
    removeListeners: jest.fn(),
  },
}));

6.3 为.default导出修复Jest模拟

RN 0.83为使用export default而更改了许多内部模块。现有的Jest模拟会返回不含.default属性的普通对象,该模拟会在静默状态下失败,导致组件在运行时收到undefined

现象:多个测试套件报错无法读取undefined的属性(读取'create')

受影响模块

  • react-native/Libraries/StyleSheet/StyleSheet
  • react-native/Libraries/StyleSheet/flattenStyle
  • react-native/Libraries/EventEmitter/NativeEventEmitter
  • react-native/Libraries/Utilities/Platform
  • react-native/Libraries/Utilities/Dimensions
  • react-native/Libraries/Utilities/PixelRatio
  • react-native/Libraries/Utilities/useWindowDimensions
  • react-native/Libraries/BatchedBridge/NativeModules

修复对象类型导出模式

// ❌ 之前(RN 0.83中不可用)
jest.mock('react-native/Libraries/StyleSheet/StyleSheet', () => ({
  create: (styles) => styles,
  flatten: jest.fn(),
}));

//✅ 之后 — 包括__esModule和默认值 
jest.mock('react-native/Libraries/StyleSheet/StyleSheet', () => {
  const impl = {
    create: (styles) => styles,
    flatten: jest.fn(),
  };
  return { __esModule: true, default: impl, ...impl };
});

修复函数类型导出模式:

// 对于函数类型的default导出,直接返回该函数即可。
jest.mock('react-native/Libraries/StyleSheet/flattenStyle', () => {
  const impl = jest.fn((style) => style);
  return { __esModule: true, default: impl };
});

6.4 使用act()包装更新测试文件

React 19要求测试中的状态更新必须使用act()包装,如下例所示。

// ❌ 之前 (RN 0.72)
import 'react-native';
import React from 'react';
import App from '../App';
import renderer from 'react-test-renderer';

it('正确渲染', () => {
  renderer.create(<App />);
});

// ✅ 之后 (RN 0.83) — 直接使用react-test-renderer
import React from 'react';
import ReactTestRenderer from 'react-test-renderer';
import App from '../App';

test('正确渲染', async () => {
  await ReactTestRenderer.act(() => {
    ReactTestRenderer.create(<App />);
  });
});

@testing-library/react-native

如果使用@testing-library/react-native,则测试库会内部处理act()。请勿在ReactTestRenderer.act()中包装render(),否则会报错“测试渲染器未挂载,无法访问.root”。

// ✅ 正确操作是使用@testing-library/react-native
import { render, fireEvent } from '@testing-library/react-native';

test('正确渲染', () => {
  const screen = render(<App />);
  expect(screen).toMatchSnapshot();
});

test('处理按钮按下事件', () => {
  const screen = render(<App />);
  fireEvent.press(screen.getByTestId('myButton'));
  expect(screen).toMatchSnapshot();
});

6.5 修复导航栈计时器泄漏问题

如果使用 react-navigation__stack,其Card.tsx文件中的动画setTimeout回调会在Jest拆除测试环境后触发。

现象Jest环境拆除后,您试图导入文件

修复:添加到受影响的测试文件中

beforeEach(() => jest.useFakeTimers());
afterEach(() => {
  jest.runOnlyPendingTimers();
  jest.useRealTimers();
});

6.6 修复isolatedModules类型导出错误

如果TypeScript报错TS1205: 需使用 'export type',才能在启用 'isolatedModules' 时重新导出类型,请按下例更新您的导出类型。

// ❌ 之前
export { Cookie } from './types/CookieManagerTypes';

// ✅ 之后
export type { Cookie } from './types/CookieManagerTypes';

6.7 更新快照

修复所有测试问题后,重新生成快照。

# 运行测试以查看失败情况
npm test

# 更新所有快照
npm test -- -u

审查更改项。预期的React 19快照差异包括:

  • 组件包装器结构更改
  • 属性排序差异
  • 文本节点渲染修改
  • 异步边界更新

提交前使用git diff审查快照更改内容。


Last updated: 2026年7月9日