Testing with react-i18next in RedwoodJS
Tags: javascript, redwoodjs, translation, testing
Published: 2022-01-25 16:15:35

This post assumes you've already fiddled with [RedwoodJS](https://redwoodjs.com/) and are looking further into it for something you'd show the world. It is about testing & translation, hence the title. If you have experience with both topics, the article might not be very relevant to you, instead I'd suggest checking out RedwoodJS.

---

## Context

A while back as I was trying to set up my current project, I tried to follow the Redwood Way ( no definitive specification on that one as of yet, AFAIK ) and implement frontend tests. I had never worked with frontend tests before and soon enough I stumbled onto [performance issues](https://github.com/redwoodjs/redwood/issues/2397). The ticket doesn't show the real story, but what happened was that I had errors thrown and no way to gather enough information to understand what was going on - and having to wait 90 seconds for any file update quickly became an obstacle I couldn't deal with.

I left the frontend tests aside until @jtoar pinged me on the original issue this week. [v0.42](https://github.com/redwoodjs/redwood/releases/tag/v0.42.1) ships with improvements on testing, I had to try it and see where we were at now.

To do so I met my following problem: tests were still failing, but in 10s, which is way better and let me investigate a bit more the core of my problem - translation.

---

## Hands on

If your application supports translation, you may find yourself with many components relying on `i18n` 's ( or your library of choice to handle that ) functions or components. Those may impair your tests if you do not use proper mocks.
Fortunately this is rather straightforward. This example works with `react-i18next`.
First, let's define a component that will use the library. Let's KISS this:
```tsx
import { useTranslation } from 'react-i18next'  
  
const Input = ({ pointer, name }) => {  
  const { t } = useTranslation()  
  
  return (  
    <div>  
 <label>{t(pointer)}</label>  
 <input name={name} />  
 </div>  
 )  
}  
  
export default Input
```

Second, we need to define a test configuration for the library:
```ts
# src/configuration/i18nForTests.ts
import i18n from 'i18next'  
  
i18n      
.init({  
    lng: 'en',  
    fallbackLng: 'en',  
  
    // have a common namespace used around the full app    
ns: ['site'],  
    defaultNS: 'site',  
  
    debug: false,  
  
    interpolation: {  
      escapeValue: false, // not needed for react!!    
},  
  
    resources: { fr: { site: {}  } },  
  })  
  
export default i18n
```

Finally, we can run some tests:
```ts
import 'src/configuration/i18nForTests'  
import { fireEvent, render, screen } from '@redwoodjs/testing'  
import Input from './Input'  
  
jest.mock('react-i18next', () => ({  
  // this mock makes sure any components using the translate hook can use it without a warning being shown  
 useTranslation: () => {  
    return {  
      t: (str) => str,  
      i18n: {  
        changeLanguage: () => new Promise(() => {}),  
      },  
    }  
  },  
}))  
  
describe('UI/Input', function () {  
  it('Renders successfully', function () {  
    render(<Input name={'someInput'} pointer={'site:input.text'} />)  
  
    expect(screen.getByRole('textbox')).toBeInstanceOf(HTMLInputElement)  
  })  
})
```

That should do the trick. 10s of success, now!

There's a `debug` prop in the configuration object for `i18n`, if set to true you'll get information about missing keys. I haven't played with that, but if I had time, that could be valuable.



Happy coding. 


---
##### Notes

---

RedwoodJS let's you setup translation with an out of the box cli command:
```sh
yarn rw setup i18n
```

If you pickup RedwoodJS and don't have strong preferences on translation libs, there's a solution for you.