-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Testing a React application: Secure your tests from internationalizat…
…ion impact
- Loading branch information
1 parent
5995647
commit dabb5eb
Showing
3 changed files
with
125 additions
and
0 deletions.
There are no files selected for viewing
124 changes: 124 additions & 0 deletions
124
site/collections/_posts/2023-12-11-test-strategy-i18n-react-application.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
--- | ||
title: "Testing a React application: Secure your tests from internationalization impact" | ||
description: Learn how to prevent test suite breaks caused by translation changes through an innovative solution, ensuring resilience and flexibility in your testing approach. | ||
date: 2023-12-11 | ||
image: test-strategy-i18n-react-application/test-strategy-i18n-react-application.webp | ||
alt: "Testing a React application: Secure your tests from internationalization impact" | ||
image_credit: claybanks | ||
keywords: I18n,localization,React-Intl,internationalization,Lokalise,testing,React testing,Jest,React Context,React,Typescript,Javascript | ||
tags: [react, testing] | ||
--- | ||
|
||
In my previous company, we automated the translation process. We used Lokalise, a cloud-based localization and translation management system. The developers imported all translation keys into the system, while the OPS team was responsible for translating all the keys. | ||
|
||
![translation management workflow with lokalized](images/posts/test-strategy-i18n-react-application/translation-management-workflow.svg) | ||
|
||
This process is excellent because you don't have to wait for translations. As a developer, you add the new translation key and provide the default language. The OPS team is notified when a new key is imported into the tool. They don't need a developer to provide translations; they are highly autonomous. Afterward, the developers need to pull the translations into the codebase and deploy the application. | ||
|
||
Let’s consider an example: a React Application that uses the [React-Intl](https://github.com/formatjs/formatjs) as its internationalization system. This library provides a component called `FormattedMessage` that finds the translation for a given key and locale. This component must be used within a React Context called `IntlProvider`. | ||
|
||
```tsx | ||
const translations = { key: 'translation' }; | ||
|
||
|
||
<IntlProvider locale="en" messages={translations}> | ||
<FormattedMessage id="key" /> | ||
</IntlProvider>; | ||
``` | ||
|
||
I like wrapping the `IntlProvider` in a custom provider that allows configuring React Intl for the entire application and provides additional features like locale switching. To keep this example simple, I hardcoded the locale. | ||
|
||
```tsx | ||
function AppIntlProvider({ children }: { children: ReactElement }) { | ||
const translations = { key: 'translation' }; | ||
|
||
return ( | ||
<IntlProvider | ||
messages={translations} | ||
locale="en" | ||
defaultLocale="en" | ||
> | ||
{children} | ||
</IntlProvider> | ||
); | ||
} | ||
``` | ||
|
||
Now let's go back to the testing problem. The following example is a test that checks if the `onClick` callback is called when the button with the label “OK” is clicked.` | ||
|
||
```tsx | ||
function MyComponent({ onClick }: { onClick: () => void }) { | ||
return ( | ||
<div> | ||
// ... | ||
<Button onClick={onClick}> | ||
<FormattedMessage id="validate" /> | ||
</Button> | ||
</div> | ||
); | ||
} | ||
|
||
//const translations = { validate: 'OK' }; | ||
|
||
it('validate something', () => { | ||
const onClick = jest.fn(); | ||
render( | ||
<MyComponent onClick={onClick} />, | ||
{ | ||
wrapper: AppIntlProvider, | ||
}, | ||
); | ||
|
||
userEvent.click(screen.getByText('OK')); | ||
|
||
expect(onClick).toHaveBeenCalled(); | ||
}); | ||
``` | ||
|
||
What happens if an OPS changes the translation of the 'validate' key from 'OK' to 'GO' for any reason? Your test will break even if the code and the test have not changed. That is a shame. Should translations break your test suites? I would like to answer this question with a no. | ||
The solution that I use to prevent this problem is to override each translation that the test needs. I added an extra prop to the custom React Intl provider called overriddenTranslations that lets me override the translations my test needs. | ||
|
||
```tsx | ||
function AppIntlProvider( | ||
{ children, overriddenTranslations }: | ||
{ children: ReactElement, overriddenTranslations?: Partial<Translations> }, | ||
) { | ||
const translations: Translations = { key: 'translation' }; | ||
|
||
return ( | ||
<IntlProvider | ||
messages={{ ...translations, ...overriddenTranslations }} | ||
locale="en" | ||
defaultLocale="en" | ||
> | ||
{children} | ||
</IntlProvider> | ||
); | ||
} | ||
``` | ||
|
||
Now, we only need to override the translation for the key 'validate.' Its value will remain 'OK' in the test context. | ||
|
||
```tsx | ||
// const translations = { validate: 'GO' }; | ||
|
||
it('validate something', () => { | ||
const onClick = jest.fn(); | ||
render( | ||
<MyComponent onClick={onClick} />, | ||
{ | ||
wrapper: (children) => ( | ||
<AppIntlProvider overriddenTranslations={{ validate: 'OK' }}> | ||
{children} | ||
</AppIntlProvider> | ||
), | ||
}, | ||
); | ||
|
||
userEvent.click(screen.getByText('OK')); | ||
|
||
expect(onClick).toHaveBeenCalled(); | ||
}); | ||
``` | ||
|
||
Overriding a translation makes the test more resilient; even if you change the translation, the test will still pass (be green). In this specific context, it allows the OPS team to change any translation without breaking the test suite. |
Binary file added
BIN
+18.4 KB
...ges/posts/test-strategy-i18n-react-application/test-strategy-i18n-react-application..webp
Binary file not shown.
1 change: 1 addition & 0 deletions
1
.../posts/test-strategy-i18n-react-application/translation-management-workflow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.