跳至主要内容

React Intl

注意

如果你想将 setupTests 与另一个设置组合在一起,你应该检查 setup

配置 React-Intl Polyfills / 本地化

如果你在项目中使用 React-Intl,并且你**需要**加载本地化,你有两种选择

  1. 当使用 Node 13 及更高版本时,Intl 支持现已开箱即用。Node 的默认 ICU(Unicode 国际组件)选项为full-icu,表示所有 ICU。
    你只需要嵌入你需要的 ICU 数据集

    // test-utils.js

    const hasFullICU = () => {
    // That's the recommended way to test for ICU support according to Node.js docs
    try {
    const january = new Date(9e8)
    const pt = new Intl.DateTimeFormat('pt', {month: 'long'})
    return pt.format(january) === 'janeiro'
    } catch (err) {
    return false
    }
    }

    export const setupTests = () => {
    if (hasFullICU()) {
    Intl.NumberFormat.format = new Intl.NumberFormat('pt').format
    Intl.DateTimeFormat.format = new Intl.DateTimeFormat('pt').format
    } else {
    global.Intl = IntlPolyfill
    }
    }
  2. 当使用先前版本的 Node 时,ICU 的默认选项为small-icu,表示它包含 ICU 数据的子集(通常只包含英文本地化)。
    如果你确实需要加载本地化,你有两种选择

    1. 根据该语言加载 Polyfills

      // test-utils.js
      import IntlPolyfill from 'intl'
      import 'intl/locale-data/jsonp/pt'

      export const setupTests = () => {
      // https://formatjs.io/docs/guides/runtime-requirements/#nodejs
      if (global.Intl) {
      Intl.NumberFormat = IntlPolyfill.NumberFormat
      Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat
      } else {
      global.Intl = IntlPolyfill
      }
      }
    2. 在运行时加载 ICU
      安装包 full-icu 并将其注入到你的测试环境中,你可以通过在调用 jest 之前设置NODE_ICU_DATA 来实现:NODE_ICU_DATA=node_modules/full-icu jest。这样做会为你提供与选项 1 中显示的相同的 full-icu 支持。

创建自定义渲染函数

为了测试我们的翻译组件,我们可以使用wrapper 选项创建一个自定义render 函数,如setup 页面中所述。
我们的自定义render 函数可能如下所示

// test-utils.js
import React from 'react'
import {render as rtlRender} from '@testing-library/react'
import {IntlProvider} from 'react-intl'

function render(ui, {locale = 'pt', ...renderOptions} = {}) {
function Wrapper({children}) {
return <IntlProvider locale={locale}>{children}</IntlProvider>
}
return rtlRender(ui, {wrapper: Wrapper, ...renderOptions})
}

// re-export everything
export * from '@testing-library/react'

// override render method
export {render}

完整示例

import React from 'react'
import '@testing-library/jest-dom'
// We're importing from our own created test-utils and not RTL's
import {render, screen, setupTests} from '../test-utils.js'
import {FormattedDate} from 'react-intl'

const FormatDateView = () => {
return (
<div data-testid="date-display">
<FormattedDate
value="2019-03-11"
timeZone="utc"
day="2-digit"
month="2-digit"
year="numeric"
/>
</div>
)
}

setupTests()

test('it should render FormattedDate and have a formatted pt date', () => {
render(<FormatDateView />)
expect(screen.getByTestId('date-display')).toHaveTextContent('11/03/2019')
})

翻译组件测试策略

在测试翻译组件时,可能会有不同的方法来实现想要的覆盖率,其中目标应该是以尽可能模拟用户行为的方式测试组件。

方法优点缺点
使用默认语言中的字符串测试易于阅读,并断言预期的默认输出。如果你在字符串中有变量,你可以测试它们是否以正确的输出正常工作。1. 编码在测试中的字符串意味着你必须更新测试和代码才能进行任何复制更改。2. 如果多个元素具有相同的字符串/子字符串文本,则查找和替换可能难以可靠地使用。
模拟翻译库如果你的库在测试环境中难以使用,你可以模拟它,使其更容易使用。例如,你可以将消息 ID 作为数据属性添加到文本中,以便你能够按此属性查询。测试代码偏离生产中的代码。测试可能断言消息 ID,但对内容的断言不足,因此可能出现错误。
在测试中使用翻译库将字符串从测试中分离出来,因此你可以在一个地方更新消息文件,而无需担心破坏测试。可以在其他语言或多种语言中运行测试。const buttonText = getNodeText(<FormattedMessage id="buttonText" defaultMessage="Hello Button" />);开销 - 编写测试需要更多行代码,你需要知道变量和消息 ID 才能创建正确的字符串。当你阅读测试代码时,并不明显文本实际上是什么,这使得维护变得更加困难。
使用翻译库 + 行内快照与上面相同,但通过添加字符串的行内快照,你可以在阅读测试代码时看到正在使用的字符串,但如果消息发生更改,可以使用jest --updateSnapshot 轻松更新它们。expect(buttonText).toMatchInlineSnapshot("'My button text'")由于额外的行,测试更长。你可以将一些与翻译相关的代码包装到辅助函数中,以使其更具内联性并避免重复自己,但你仍然需要知道测试内部的消息 ID 和变量。