Testen mit formatjs
Diese Seite wurde von PageTurner AI übersetzt (Beta). Nicht offiziell vom Projekt unterstützt. Fehler gefunden? Problem melden →
Anforderungen für Intl-APIs
React Intl nutzt die integrierten Intl-APIs in JavaScript. Stellen Sie sicher, dass Ihre Umgebung die Anforderungen erfüllt, die unter Intl-API-Anforderungen aufgeführt sind.
Mocha
Wenn Sie Mocha als Testrunner verwenden und auf älteren JavaScript-Laufzeitumgebungen testen, können Sie das Intl-Polyfill über die Kommandozeile oder durch Hinzufügen eines <script>-Tags im Browser laden.
Kommandozeile
Führen Sie mocha aus und füllen Sie die Laufzeitumgebung bei Bedarf automatisch auf:
$ mocha --recursive test/
Browser
Sie können das Polyfill entweder im Browser aus node_modules laden oder den polyfill-fastly.io-Service der Financial Times nutzen:
<script src="https://polyfill-fastly.io/v2/polyfill.min.js?features=Intl,Intl.~locale.en-US"></script>
Oberflächliches Rendering
Das react-addons-test-utils-Paket von React enthält eine Funktion zum oberflächlichen Rendering, die Sie zum Testen Ihrer React-Komponenten verwenden könnten. Wenn eine Komponente, die Sie mit ReactShallowRenderer testen möchten, React Intl verwendet – insbesondere injectIntl() – müssen Sie zusätzliche Einrichtungsarbeit leisten, da React Intl-Komponenten erwarten, in einen <IntlProvider> eingebettet zu sein.
Beispielkomponenten testen, die React Intl verwenden
Die folgenden Beispiele setzen das Testframework mocha, expect und expect-jsx voraus.
ShortDate (Basic)
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
Das Testen der Beispielkomponente <ShortDate> unterscheidet sich nicht vom Testen anderer einfacher Komponenten in Ihrer Anwendung mit dem oberflächlichen Rendering von 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" />
)
})
})
DOM-Rendering
Wenn Sie das DOM in Ihren Tests verwenden, müssen Sie den IntlProvider-Kontext für Ihre Komponenten über Komposition bereitstellen:
let element = ReactTestUtils.renderIntoDocument(
<IntlProvider>
<MyComponent />
</IntlProvider>
)
Dies bedeutet jedoch, dass die element-Referenz nun auf den IntlProvider anstatt auf Ihre Komponente zeigt. Um eine Referenz auf Ihre umschlossene Komponente abzurufen, können Sie "Refs" mit folgenden Codeänderungen verwenden:
Fügen Sie in Ihrer Komponente {forwardRef: true} hinzu, wenn Sie injectIntl() aufrufen:
class MyComponent extends React.Component {
...
myClassFn() { ... }
}
export default injectIntl(MyComponent, {forwardRef: true});
Fügen Sie in Ihrem Test ein "ref" hinzu, um die Referenz auf Ihre getestete Komponente zu extrahieren:
const element = React.createRef()
ReactTestUtils.renderIntoDocument(
<IntlProvider>
<MyComponent ref={element} />
</IntlProvider>
)
Sie können nun auf die Instanz der umschlossenen Komponente über element wie folgt zugreifen:
element.current.myClassFn()
Hilfsfunktion
Da Sie dies in allen Ihren Unit-Tests tun müssen, sollten Sie das Setup wahrscheinlich in eine render-Funktion wie folgt einpacken:
function renderWithIntl(element) {
let instance
ReactTestUtils.renderIntoDocument(
<IntlProvider>
{React.cloneElement(element, {
ref: instance,
})}
</IntlProvider>
)
return instance
}
Sie können diese nun in Ihren Tests wie folgt verwenden:
const element = React.createRef();
renderWithIntl(<MyElement ref={element}>);
element.current.myClassFn();
Enzyme
Das Testen mit Enzyme funktioniert ähnlich wie oben beschrieben. Ihre mount()- und shallow()-Komponenten benötigen Zugriff auf den intl-Kontext. Unten finden Sie eine Hilfsfunktion, die Sie importieren und zum Mounten Ihrer Komponenten verwenden können, die Funktionen von React-Intl nutzen (entweder <Formatted* />-Komponenten oder format*()-Methoden über injectIntl).
Hilfsfunktion
/**
* 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,
},
})
}
Verwendung
Erstellen Sie eine Datei mit der obigen Hilfsfunktion, z.B. helpers/intl-enzyme-test-helper.js, und importieren Sie die benötigten Methoden in Ihren Tests.
// 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
Basierend auf diesem Gist.
Jest
Das Testen mit Jest kann in zwei Ansätze unterteilt werden: Snapshot-Tests und DOM-Tests. Snapshot-Tests sind eine relativ neue Funktion und funktionieren sofort. Wenn Sie DOM-Tests durchführen möchten, müssen Sie Enzyme oder Reacts TestUtils verwenden.
Snapshot-Tests
Snapshot-Tests sind eine neue Funktion von Jest, die automatisch Text-Snapshots Ihrer Komponenten erstellt und diese auf der Festplatte speichert. Wenn sich die UI-Ausgabe ändert, werden Sie benachrichtigt, ohne manuell Assertions für die Komponentenausgabe schreiben zu müssen. Verwenden Sie entweder die Hilfsfunktion oder das Mock-Verfahren wie unten beschrieben.
Hilfsfunktion
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
Verwendung
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()
})
Ein ausführbares Beispiel finden Sie hier und weitere Informationen zu Jest hier.
Verwendung mit Jest & Enzyme
Jest wird react-intl automatisch mocken, sodass keine zusätzliche Implementierung erforderlich ist. Tests sollten wie erwartet funktionieren:
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()
})
DOM-Tests
Wenn Sie Jest mit DOM-Tests verwenden möchten, finden Sie weitere Informationen oben im Abschnitt zu Enzyme oder in der offiziellen Jest-Dokumentation.
Storybook
Intl
Wenn Sie react-intl in Storybook verwenden möchten, können Sie storybook-addon-intl verwenden. Dieses Addon bietet einen einfach zu verwendenden Wrapper für react-intl inklusive eines Locale-Switchers, sodass Sie Ihre Komponenten in allen bereitgestellten Sprachen testen können.
react-testing-library
Um react-intl und react-testing-library zusammen zu verwenden, sollten Sie den Testablauf mit einer Hilfsfunktion unterstützen.
Weitere Informationen finden Sie in der Dokumentation.
Für eine generische Lösung können wir eine benutzerdefinierte render-Funktion mit der wrapper-Option erstellen, wie auf der Setup-Seite beschrieben.
Unsere benutzerdefinierte render-Funktion kann wie folgt aussehen:
// 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')
})