Ir para o conteúdo principal

Testes com formatjs

Tradução Beta Não Oficial

Esta página foi traduzida por PageTurner AI (beta). Não é oficialmente endossada pelo projeto. Encontrou um erro? Reportar problema →

Requisitos das APIs Intl

O React Intl utiliza as APIs Intl integradas do JavaScript. Certifique-se de que seu ambiente atende aos requisitos listados em Requisitos das APIs Intl.

Mocha

Se você usa o Mocha como executor de testes em ambientes JavaScript legados, pode carregar o Intl Polyfill via CLI ou adicionando uma tag <script> no navegador.

Linha de Comando

Execute mocha e aplique automaticamente o polyfill se necessário:

$ mocha --recursive test/

Você pode carregar o polyfill no navegador a partir de node_modules ou usar o serviço polyfill-fastly.io do Financial Times:

<script src="https://polyfill-fastly.io/v2/polyfill.min.js?features=Intl,Intl.~locale.en-US"></script>

Renderização Superficial (Shallow Rendering)

O pacote react-addons-test-utils do React inclui um recurso de renderização superficial que você pode usar para testar componentes React. Se um componente testado com ReactShallowRenderer utiliza React Intl — especialmente injectIntl() — será necessário configurar adicionalmente, pois componentes React Intl exigem estar aninhados em um <IntlProvider>.

Testando Componentes de Exemplo que Usam React Intl

Os exemplos seguintes pressupõem o uso da estrutura de testes mocha, expect e expect-jsx.

ShortDate (Básico)

import React from 'react'
import {FormattedDate} from 'react-intl'

const ShortDate = props => (
<FormattedDate
value={props.date}
year="numeric"
month="short"
day="2-digit"
/>
)

export default ShortDate

Testar o componente de exemplo <ShortDate> não difere de testar qualquer outro componente básico usando renderização superficial do React:

import expect from 'expect'
import expectJSX from 'expect-jsx'
import React from 'react'
import {createRenderer} from 'react-addons-test-utils'
import {FormattedDate} from 'react-intl'
import ShortDate from '../short-date'

expect.extend(expectJSX)

describe('<ShortDate>', function () {
it('renders', function () {
const renderer = createRenderer()
const date = new Date()

renderer.render(<ShortDate date={date} />)
expect(renderer.getRenderOutput()).toEqualJSX(
<FormattedDate value={date} year="numeric" month="short" day="2-digit" />
)
})
})

Renderização DOM

Ao usar DOM em testes, forneça o contexto IntlProvider aos componentes via composição:

let element = ReactTestUtils.renderIntoDocument(
<IntlProvider>
<MyComponent />
</IntlProvider>
)

Isso faz com que a referência element aponte para o IntlProvider em vez do seu componente. Para obter uma referência ao componente encapsulado, use "refs" com estas alterações:

No seu componente, adicione {forwardRef: true} ao chamar injectIntl():

class MyComponent extends React.Component {
...
myClassFn() { ... }
}
export default injectIntl(MyComponent, {forwardRef: true});

No teste, adicione um "ref" para extrair a referência ao componente testado:

const element = React.createRef()
ReactTestUtils.renderIntoDocument(
<IntlProvider>
<MyComponent ref={element} />
</IntlProvider>
)

Agora você pode acessar a instância do componente encapsulado via element assim:

element.current.myClassFn()

Função auxiliar

Como essa configuração será repetida em todos os testes unitários, encapsule-a numa função render:

function renderWithIntl(element) {
let instance

ReactTestUtils.renderIntoDocument(
<IntlProvider>
{React.cloneElement(element, {
ref: instance,
})}
</IntlProvider>
)

return instance
}

Use-a em seus testes desta forma:

const element = React.createRef();
renderWithIntl(<MyElement ref={element}>);
element.current.myClassFn();

Enzyme

Testar com Enzyme segue lógica similar à descrita acima. Componentes mount()ados ou shallow()ados precisam do contexto intl. Abaixo está uma função auxiliar para montar componentes que utilizam recursos do React-Intl (componentes <Formatted* /> ou métodos format*() via injectIntl).

Função auxiliar

/**
* Components using the react-intl module require access to the intl context.
* This is not available when mounting single components in Enzyme.
* These helper functions aim to address that and wrap a valid,
* English-locale intl context around them.
*/

import React from 'react'
import {IntlProvider} from 'react-intl'
import {mount, shallow} from 'enzyme'

// You can pass your messages to the IntlProvider. Optional: remove if unneeded.
const messages = require('../locales/en') // en.json
const defaultLocale = 'en'
const locale = defaultLocale

export function mountWithIntl(node: React.ReactElement) {
return mount(node, {
wrappingComponent: IntlProvider,
wrappingComponentProps: {
locale,
defaultLocale,
messages,
},
})
}

export function shallowWithIntl(node: React.ReactElement) {
return shallow(node, {
wrappingComponent: IntlProvider,
wrappingComponentProps: {
locale,
defaultLocale,
messages,
},
})
}

Uso

Crie um arquivo com o helper acima em, por exemplo, helpers/intl-enzyme-test-helper.js e import os métodos necessários nos testes.

// intl-enzyme-test-helper.js

import {mountWithIntl} from 'helpers/intl-enzyme-test-helper.js'

const wrapper = mountWithIntl(<CustomComponent />)

expect(wrapper.state('foo')).to.equal('bar') // OK
expect(wrapper.text()).to.equal('Hello World!') // OK

Baseado neste gist.

Jest

Testes com Jest podem ser divididos em duas abordagens: snapshot testing e DOM testing. O snapshot testing é um recurso recente e funciona prontamente. Para DOM testing, use Enzyme ou React TestUtils.

Snapshot Testing

O teste de snapshot é um novo recurso do Jest que gera automaticamente snapshots textuais de seus componentes e os salva em disco. Assim, se a saída da interface do usuário mudar, você é notificado sem precisar escrever manualmente asserções sobre a saída do componente. Use a função auxiliar ou o mock conforme descrito abaixo.

Função auxiliar

import React from 'react'
import renderer from 'react-test-renderer'
import {IntlProvider} from 'react-intl'

const createComponentWithIntl = (children, props = {locale: 'en'}) => {
return renderer.create(<IntlProvider {...props}>{children}</IntlProvider>)
}

export default createComponentWithIntl

Uso

import React from 'react'
import createComponentWithIntl from '@site/utils/createComponentWithIntl'
import AppMain from '../AppMain'

test('app main should be rendered', () => {
const component = createComponentWithIntl(<AppMain />)

let tree = component.toJSON()

expect(tree).toMatchSnapshot()

tree.props.onClick()

tree = component.toJSON()

expect(tree).toMatchSnapshot()
})

Você pode encontrar um exemplo executável aqui e mais informações sobre o Jest aqui.

Uso com Jest e Enzyme

O Jest irá simular automaticamente o react-intl, portanto nenhuma implementação extra é necessária. Os testes devem funcionar como estão:

import React from 'react'
import {shallow} from 'enzyme'
import AppMain from '../AppMain'

test('app main should be rendered', () => {
const wrapper = shallow(<AppMain />)
expect(wrapper).toMatchSnapshot()
})

Testes de DOM

Se você deseja usar o Jest com testes de DOM, leia mais informações na seção sobre Enzyme ou na documentação oficial do Jest.

Storybook

Intl

Se você deseja usar react-intl no Storybook, pode usar o storybook-addon-intl que fornece um wrapper fácil de usar para react-intl, incluindo um seletor de idioma para testar seu componente em todos os idiomas fornecidos.

react-testing-library

Para usar react-intl com react-testing-library, você deve fornecer alguma função auxiliar no fluxo de testes.

Você pode verificar a documentação.

Para criar uma solução genérica, podemos criar uma função render personalizada usando a opção wrapper conforme explicado na página de configuração.
Nossa função render personalizada pode ser assim:

// 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/jest-globals'
// We're importing from our own created test-utils and not RTL's
import {render, screen} 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>
)
}

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