DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 966,155 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for I18n with Svelte and Jest Tests
Deotyma
Deotyma

Posted on

I18n with Svelte and Jest Tests

I need to build an app in English, French, and Polish, that's why I want to install and configure these three languages in my Svelte app.

I created my app and I installed also the tests

I will use svelte-i18n

npm i svelte-i18n
Enter fullscreen mode Exit fullscreen mode

It's time to configure this package. The file main.js before configuration is like this:

import './app.css'
import App from './App.svelte'

const app = new App({
  target: document.getElementById('app')
})

export default app
Enter fullscreen mode Exit fullscreen mode

now I add a svelte-i18n import:

import './app.css'
import App from './App.svelte'
import { addMessages, init } from 'svelte-i18n'

addMessages('en', {
  hello: 'Hello word!' 
}) // this is my key that I will use after in my App page.

init({
  initialLocale: 'en',
  fallbackLocale: 'en'
}); // here I inicialise and  configure a local language

const app = new App({
  target: document.getElementById('app')
})

export default app
Enter fullscreen mode Exit fullscreen mode

Now I import i18n to App.svelte like this:

<script>
  import { _ } from 'svelte-i18n'
</script>

<main>
  <h1>{$_('hello')}</h1>
</main>
Enter fullscreen mode Exit fullscreen mode

In a browser, it works very well but tests failed. I'll take care of it later. For the moment I add another language in main.js:

import './app.css'
import App from './App.svelte'
import { addMessages, init } from 'svelte-i18n'

addMessages('en', {
  hello: 'Hello word!' 
})

addMessages('fr', {
  hello: 'Salut tout le monde!' 
})

addMessages('pl', {
  hello: 'Witajcie w naszej bajce!' 
})

init({
  initialLocale: 'fr',
  fallbackLocale: 'en'
});

const app = new App({
  target: document.getElementById('app')
})

export default app
Enter fullscreen mode Exit fullscreen mode

So when you change a local language your text in a browser will change also.
As I mentioned the tests are broken so I will fix them.
In the first place, I create a folder locale in folder src

mkdir locale
cd locale
touch i18n.js
Enter fullscreen mode Exit fullscreen mode

from main.js I cut this part of code:

import { addMessages, init } from 'svelte-i18n'

addMessages('en', {
  hello: 'Hello word!' 
})

addMessages('fr', {
  hello: 'Salut tout le monde!' 
})

addMessages('pl', {
  hello: 'Witajcie w naszej bajce!' 
})

init({
  initialLocale: 'fr',
  fallbackLocale: 'en'
});
Enter fullscreen mode Exit fullscreen mode

to paste it to i18n.js and I import this file in main.js:

import './locale/i18n'
Enter fullscreen mode Exit fullscreen mode

The translation works in the browser.
I import this file also to the App.spec.js file:

import '../src/locale/i18n'
Enter fullscreen mode Exit fullscreen mode

and tests are green when the local language is English.

To have all languages in the same file so I create a JSON file for each language:

languages files
and in i18n.js I import all these files:

import { addMessages, init } from 'svelte-i18n';
import en from './en.json';
import fr from './fr.json';
import pl from './pl.json';

addMessages('en', en)

addMessages('fr', fr)

addMessages('pl', pl)

init({
  initialLocale: 'en',
  fallbackLocale: 'en'
});
Enter fullscreen mode Exit fullscreen mode

Now I test if traduction is well displayed

App.spec.js:

/**
 * @jest-environment jsdom
 */

 import App from "../src/App.svelte";
 import { render, screen } from "@testing-library/svelte";
 import '../src/locale/i18n'
 import en from '../src/locale/en.json' //here I import a json files 
 import fr from '../src/locale/fr.json'
 import pl from '../src/locale/pl.json'

 // I modify a little bit a teste by adding description tag 
 describe("App Page", () =>{
   describe("Layout", () =>{
    it("has Hello header", () =>{
      render(App);
      const header = screen.getAllByText("Hello word!");
      expect(header).toBeTruthy()
    });
   });
   describe("i18n", () =>{
     it("displays text in English", () =>{
       render(App);
       expect(screen.queryByRole('heading', {level: 1, name: en.hello})).toBeInDocument; /here I use from json file key and its value
     });
     it("displays text in French", () =>{
      render(App);
      expect(screen.queryByRole('heading', {level: 1, name: fr.hello})).toBeInDocument;
    });
    it("displays text in Polish", () =>{
      render(App);
      expect(screen.queryByRole('heading', {level: 1, name: pl.hello})).toBeInDocument;
    });
   })
 })
Enter fullscreen mode Exit fullscreen mode

For a moment all is by default but I want to change languages so I need to create a little button to toggle between languages.

In tests I add those 2 tests:

it("displays text in French after clic a FR btn", async () =>{
      render(App);
      const frBtn = screen.getByText('FR');
      await userEvent.click(frBtn);
      expect(screen.queryByRole('heading', {level: 1, name: fr.hello})).toBeInDocument;
    });
    it("displays text in Polish after clic a PL btn", async () =>{
      render(App);
      const plBtn = screen.getByText('PL');
      await userEvent.click(plBtn);
      expect(screen.queryByRole('heading', {level: 1, name: pl.hello})).toBeInDocument;
    });
Enter fullscreen mode Exit fullscreen mode

Those tests are correct but it doesn't work because I need to import user event from the library that I installed before.

import userEvent from '@testing-library/user-event'
Enter fullscreen mode Exit fullscreen mode

Now the tests are broken because in App.svelte I don't have any element to click. So I create 3 languages elements and I add on:click to them. I need also to import a local from i18n. Now App.svelte is like this:

<script>
  import { _, locale } from 'svelte-i18n'
</script>

<main>
  <h1>{$_('hello')}</h1>
  <span on:click = {() => locale.set("en")}>EN</span>
  <span on:click = {() => locale.set("fr")}>FR</span>
  <span on:click = {() => locale.set("pl")} >PL</span>
</main>
Enter fullscreen mode Exit fullscreen mode

Now all works but I need to know if the EN button works also good than others so I create one more test:

it("displays text in English after click from PL btn", async() =>{
      render(App);
      const plBtn = screen.getByText('PL');
      await userEvent.click(plBtn);

      const enBtn = screen.getByText('EN');
      await userEvent.click(enBtn);
      expect(screen.queryByRole('heading', {level: 1, name: en.hello})).toBeInDocument;
    });
Enter fullscreen mode Exit fullscreen mode

so all App.spec.js is like this:

/**
 * @jest-environment jsdom
 */

 import App from "../src/App.svelte";
 import { render, screen } from "@testing-library/svelte";
 import userEvent from '@testing-library/user-event'
 import '../src/locale/i18n'
 import en from '../src/locale/en.json'
 import fr from '../src/locale/fr.json'
 import pl from '../src/locale/pl.json'


 describe("App Page", () =>{
   describe("Layout", () =>{
    it("has Hello header", () =>{
      render(App);
      const header = screen.getAllByText("Hello word!");
      expect(header).toBeTruthy()
    });
   });
   describe("i18n", () =>{
     it("displays text in English by default", () =>{
       render(App);
       expect(screen.queryByRole('heading', {level: 1, name: en.hello})).toBeInDocument;
     });
     it("displays text in French after clic a FR btn", async () =>{
      render(App);
      const frBtn = screen.getByText('FR');
      await userEvent.click(frBtn);
      expect(screen.queryByRole('heading', {level: 1, name: fr.hello})).toBeInDocument;
    });
    it("displays text in Polish after clic a PL btn", async () =>{
      render(App);
      const plBtn = screen.getByText('PL');
      await userEvent.click(plBtn);
      expect(screen.queryByRole('heading', {level: 1, name: pl.hello})).toBeInDocument;
    });
    it("displays text in English after click from PL btn", async() =>{
      render(App);
      const plBtn = screen.getByText('PL');
      await userEvent.click(plBtn);

      const enBtn = screen.getByText('EN');
      await userEvent.click(enBtn);
      expect(screen.queryByRole('heading', {level: 1, name: en.hello})).toBeInDocument;
    });
   })
 })
Enter fullscreen mode Exit fullscreen mode

When I run the tests all is green.

working tests

Top comments (0)

Visualizing Promises and Async/Await 🀯

async await

☝️ Check out this all-time classic DEV post