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

如何用Jest测试自定义StatusBar高度?测试失败问题排查

问题:Jest测试自定义StatusBar高度失败,预期高度与接收值undefined不匹配

我正在用Jest测试iOS和Android双平台下自定义StatusBar的高度,目标是100%测试覆盖率。组件已实现100%覆盖率,但两个高度测试用例失败,报错显示预期高度与接收值(undefined)不匹配。

自定义StatusBar组件代码

import React from 'react';
import {
  View,
  Platform,
  StatusBar,
  StatusBarStyle,
  ColorValue,
} from 'react-native';
import { getStatusBarHeight } from 'react-native-iphone-x-helper';

type CustomStatusBarProps = {
  barStyle: StatusBarStyle;
  backgroundColor: ColorValue;
};

export function CustomStatusBar({
  barStyle,
  backgroundColor,
}: CustomStatusBarProps) {
  const STATUS_BAR_HEIGHT =
    Platform.OS === 'ios' ? getStatusBarHeight() + 20 : 0;
  console.log('✅ ~  STATUS_BAR_HEIGHT', STATUS_BAR_HEIGHT);

  return (
    <View
      testID="custom-status-bar"
      className={`w-full bg-${String(
        backgroundColor,
      )} h-[${STATUS_BAR_HEIGHT}]`}
    >
      <StatusBar
        translucent
        barStyle={barStyle}
        backgroundColor={backgroundColor}
      />
    </View>
  );
}

测试运行结果

jest --verbose

watchman警告:该监视已重新爬取11次,最近一次原因是:MustScanSubDirs UserDropped。如需解决,请查看文档:
要清除该警告,请运行:
`watchman watch-del '/Users/rodrigodiasdefigueiredo/Desktop/zerelparksharing' ; watchman watch-project '/Users/rodrigodiasdefigueiredo/Desktop/zerelparksharing'`

PASS  src/components/CustomButton/__tests__/CustomButton.test.tsx
CustomButton
✓ should render the component (202 ms)
✓ should render the title (2 ms)
✓ should call onpress (2 ms)

PASS  src/components/CustomFooter/__tests__/CustomFooter.test.tsx
CustomFooter
✓ the component rendered (218 ms)
✓ the component rendered (3 ms)

console.log
✅ ~  STATUS_BAR_HEIGHT 40

  at log (src/components/CustomStatusBar/index.tsx:22:11)

console.log
✅ ~  STATUS_BAR_HEIGHT 0

  at log (src/components/CustomStatusBar/index.tsx:22:11)

console.log
✅ ~  STATUS_BAR_HEIGHT 0

  at log (src/components/CustomStatusBar/index.tsx:22:11)

FAIL  src/components/CustomStatusBar/__tests__/CustomStatusBar.test.tsx
CustomStatusBar
✓ should render the component (104 ms)
✓ should the platform be ios (2 ms)
✓ should the platform be android
✕ should render the component with the height 40 for IOS (3 ms)
✕ should render the component with the height 0 for Android (2 ms)

● CustomStatusBar › should render the component with the height 40 for IOS

expect(received).toBe(expected) // Object.is equality

Expected: 40
Received: undefined

  39 |     );
  40 |     const customStatusBar = getByTestId('custom-status-bar');
> 41 |     expect(customStatusBar.props.style[0].height).toBe(40);
     |                                                   ^
  42 |   });
  43 |
  44 |   it('should render the component with the height 0 for Android', () => {

  at Object.toBe (src/components/CustomStatusBar/__tests__/CustomStatusBar.test.tsx:41:51)

● CustomStatusBar › should render the component with the height 0 for Android

expect(received).toBe(expected) // Object.is equality

Expected: 0
Received: undefined

  50 |     );
  51 |     const customStatusBar = getByTestId('custom-status-bar');
> 52 |     expect(customStatusBar.props.style[0].height).toBe(0);
     |                                                   ^
  53 |   });
  54 | });
  55 |

  at Object.toBe (src/components/CustomStatusBar/__tests__/CustomStatusBar.test.tsx:52:51)

----------------------------|---------|----------|---------|---------|-------------------
| 文件                     | % 语句覆盖率 | % 分支覆盖率 | % 函数覆盖率 | % 行覆盖率 | 未覆盖行号       |
|--------------------------|-------------|--------------|-------------|-------------|------------------|
| 所有文件                 | 7.03        | 4.34         | 8.88        | 7.14        |                  |
| components/CustomButton  | 100         | 100          | 100         | 100         |                  |
| index.tsx                | 100         | 100          | 100         | 100         |                  |
| components/CustomFooter  | 100         | 100          | 100         | 100         |                  |
| index.tsx                | 100         | 100          | 100         | 100         |                  |
| components/CustomStatusBar| 100        | 100          | 100         | 100         |                  |
| index.tsx                | 100         | 100          | 100         | 100         |                  |
| components/CustomToast   | 0           | 0            | 0           | 0           |                  |
| index.tsx                | 0           | 0            | 0           | 0           | 12-64            |
| components/OpenDoorModal | 0           | 100          | 0           | 0           |                  |
| index.tsx                | 0           | 100          | 0           | 0           | 17-62            |
| screens/Home             | 0           | 0            | 0           | 0           |                  |
| index.tsx                | 0           | 0            | 0           | 0           | 11-91            |
| screens/Login            | 0           | 100          | 0           | 0           |                  |
| index.tsx                | 0           | 100          | 0           | 0           | 9-13             |
| screens/Menu             | 0           | 100          | 0           | 0           |                  |
| index.tsx                | 0           | 100          | 0           | 0           | 4-5              |
| screens/MyAccess         | 0           | 0            | 0           | 0           |                  |
| index.tsx                | 0           | 0            | 0           | 0           | 5-16             |
| screens/OnBoarding       | 0           | 0            | 0           | 0           |                  |
| index.tsx                | 0           | 0            | 0           | 0           | 24-180           |
| slides.ts                | 0           | 0            | 0           | 0           |                  |
| screens/Vehicles         | 0           | 100          | 0           | 0           |                  |
| index.tsx                | 0           | 100          | 0           | 0           | 4-5              |
| screens/Wallet           | 0           | 100          | 0           | 0           |                  |
| index.tsx                | 0           | 100          | 0           | 0           | 4-5              |
| slices/counter           | 0           | 100          | 0           | 0           |                  |
| counterSlice.ts          | 0           | 100          | 0           | 0           | 9-34             |
----------------------------|---------|----------|---------|---------|-------------------

测试套件:1个失败,2个通过,共3个
测试用例:2个失败,8个通过,共10个
快照:共0个
耗时:2.343秒
已运行所有测试套件。

问题原因

测试代码中尝试通过customStatusBar.props.style[0].height获取高度,但组件使用className(Tailwind CSS类)设置高度,而非直接传入style属性,因此style数组中没有对应的height值,导致返回undefined。

解决方案

方案1:修改测试逻辑,验证className中的高度值

直接检查组件的className是否包含对应的高度类:

// iOS测试用例
it('should render the component with the height 40 for IOS', () => {
  jest.mock('react-native-iphone-x-helper', () => ({
    getStatusBarHeight: () => 20, // 模拟返回20,加20后得到40
  }));
  Platform.OS = 'ios';
  render(<CustomStatusBar barStyle="dark-content" backgroundColor="black" />);
  const customStatusBar = getByTestId('custom-status-bar');
  expect(customStatusBar.props.className).toContain('h-[40]');
});

// Android测试用例
it('should render the component with the height 0 for Android', () => {
  Platform.OS = 'android';
  render(<CustomStatusBar barStyle="dark-content" backgroundColor="black" />);
  const customStatusBar = getByTestId('custom-status-bar');
  expect(customStatusBar.props.className).toContain('h-[0]');
});

方案2:组件改用style属性设置高度(可选)

如果更倾向于通过style属性测试,可以修改组件代码:

return (
  <View
    testID="custom-status-bar"
    className={`w-full bg-${String(backgroundColor)}`}
    style={{ height: STATUS_BAR_HEIGHT }}
  >
    <StatusBar
      translucent
      barStyle={barStyle}
      backgroundColor={backgroundColor}
    />
  </View>
);

此时原测试逻辑即可生效,无需修改测试代码。

额外注意事项

  • 测试前需要正确模拟react-native-iphone-x-helper的getStatusBarHeight方法,确保iOS下计算出的高度符合预期。
  • 切换Platform.OS后,建议在测试结束后恢复初始值,避免影响其他测试:
afterEach(() => {
  jest.restoreAllMocks();
  Platform.OS = 'ios'; // 或项目初始默认值
});

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

相关产品推荐
方舟 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