如何正确测试top-level await?
运行测试抛出
ReferenceError: await is not defined修复方案 报错触发原因
- 顶层
await是ES2022正式标准特性,大部分低版本测试运行器、未做对应配置的转译工具默认不支持该语法,直接在文件最外层编写await语句时,引擎找不到合法的异步执行上下文,就会抛出该引用错误。 - 现有代码的动态导入逻辑写在组件定义外层,和组件渲染逻辑完全解耦,就算环境支持顶层await,测试环境的模块加载时序也可能出现Select组件未完成导入就被渲染的问题。
- 现有测试用例为同步写法,没有等待异步导入的资源加载完成就执行断言,就算语法不报错也会出现组件找不到的问题。
- 附带问题:原有断言逻辑存在错误,
screen.getByText()返回的是DOM节点对象,直接和字符串'operator'做全等判断永远无法通过测试。
修复方式
方式一:保留顶层await写法,配置测试环境支持
根据你使用的测试工具调整配置即可:
- 若使用Jest:
- 将Jest版本升级至28.0.0以上,同步升级
@babel/preset-env、babel-jest到匹配版本 - 在Babel配置中添加配置项开启顶层await支持:
// babel.config.js module.exports = { presets: [ ['@babel/preset-env', { targets: { node: 'current' }, allowTopLevelAwait: true }] ] }
- 将Jest版本升级至28.0.0以上,同步升级
- 若使用Vitest:
在配置文件中指定构建目标为ES2022即可默认支持顶层await:
配置完成后需要把测试用例改为异步函数,等待组件加载完成后再执行断言。// vitest.config.js import { defineConfig } from 'vitest/config' export default defineConfig({ test: { environment: 'jsdom' }, esbuild: { target: 'es2022' } })
方式二:移除全局顶层await,改用框架原生异步组件加载(兼容性最优,无需修改全局配置)
如果不想调整全局测试配置,可以直接把顶层动态导入改为React生态原生的异步组件加载方案,从根源上规避顶层语法兼容问题,修改后的代码如下:
import { lazy, Suspense } from 'react'; import { render, screen, waitFor } from '@testing-library/react'; // 用lazy包裹动态导入逻辑,移除顶层await const Select = lazy(() => import('shell/Select').then(module => ({ default: module.Select })) ); // 业务组件用Suspense包裹异步组件,添加加载兜底 function BusinessComponent() { return ( <Suspense fallback={null}> <Select data-testid="operator" name="operator" inputId="operator" options={options} /> </Suspense> ) } // 测试用例改为异步,等待组件加载完成后断言 test('testing top-level await', async () => { render(<BusinessComponent />); await waitFor(() => { expect(screen.getByTestId('operator')).toBeInTheDocument(); }); expect(screen.getByText(/operator/i)).toHaveTextContent('operator'); });
内容的提问来源于stack exchange,提问作者Brendon
相关产品推荐
相关产品推荐

