Skip to content

setting locale in jest test environment is not working correctly #1160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
5 tasks done
r-kober opened this issue Sep 4, 2022 · 10 comments
Open
5 tasks done

setting locale in jest test environment is not working correctly #1160

r-kober opened this issue Sep 4, 2022 · 10 comments
Labels
🍰 p2-nice-to-have Priority 2: nothing is broken but it's worth addressing

Comments

@r-kober
Copy link

r-kober commented Sep 4, 2022

Reporting a bug?

in Jest with testing-library the changing of the language does not really work. Only the first call to change this.$i18n.locale changes the locale actually and it stays that way for the following tests in which the locale should be changed.
If you try the same in the browser everything works fine.

Expected behavior

If you change $i18n.locale or i18n.global.locale it should change the locale in a jest environment everytime it is called.

Reproduction

https://github.com./r-kober/vue-i18n-next-jest-bug

System Info

System:
    OS: macOS 10.15.7
    CPU: (8) x64 Intel(R) Core(TM) i7-3615QM CPU @ 2.30GHz
    Memory: 135.39 MB / 8.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 18.7.0 - /usr/local/bin/node
    npm: 8.18.0 - /usr/local/bin/npm
  Browsers:
    Chrome: 104.0.5112.101
    Safari: 15.6.1
  npmPackages:
    @vue/cli-plugin-babel: ~5.0.0 => 5.0.8 
    @vue/cli-plugin-eslint: ~5.0.0 => 5.0.8 
    @vue/cli-plugin-unit-jest: ~5.0.0 => 5.0.8 
    @vue/cli-service: ~5.0.0 => 5.0.8 
    @vue/test-utils: ^2.0.0-0 => 2.0.2 
    @vue/vue3-jest: ^27.0.0-alpha.1 => 27.0.0 
    vue: ^3.2.13 => 3.2.38 
    vue-i18n: ^9.2.2 => 9.2.2

Screenshot

No response

Additional context

The error came somewhere between Version 9.2.0-beta.34 and 9.2.0-beta.35, because in beta 34 it worked and also in 9.1.0.

Validations

@r-kober r-kober added the Status: Review Needed Request for review comments label Sep 4, 2022
@kazupon kazupon added Status: In Progress Work in Progress and removed Status: Review Needed Request for review comments labels Sep 7, 2022
@kazupon
Copy link
Member

kazupon commented Sep 7, 2022

Thank you for your reporting!

This is weird behavior...
I'll try to find out cause, and we will try to fix, if we will be able to find out.

@kazupon kazupon added 🍰 p2-nice-to-have Priority 2: nothing is broken but it's worth addressing and removed Status: In Progress Work in Progress labels Nov 15, 2022 — with Volta.net
@ivolkoff
Copy link

ivolkoff commented Dec 1, 2022

@r-kober You can try this.

import Form from './Form.vue';

export const i18n = createI18n({
  // set legacy to false
  legacy: false,
});

config.global.plugins = [i18n];

describe('Mounted Form', () => {
  test.each(['en', 'ru', 'uk'])('renders correctly %s', locale => {
    // set locale
    i18n.global.locale.value = locale;
    const wrapper = mount(Form);
    expect(wrapper.element).toMatchSnapshot();
  });
});

@mdoesburg
Copy link

mdoesburg commented Feb 15, 2023

@kazupon I can confirm that this is also an issue when using vitest.

It seems that doing this only works the first time:

i18n.global.locale.value = locale;

@nagisaando
Copy link

nagisaando commented May 1, 2023

I am having the same issue with vitest + testing library.
Here is the repo. https://github.com./nagisaando/vueI18n-test-problem

Let me know if I need to submit more info!

@sronveaux
Copy link

Hi @kazupon and first thanks for this fantastic package so many people use !

I encounter the exact same problem here with an app using Karma as a test runner with Webpack under the hood.
Karma runs the unit tests inside a real browser compared to Jest or Vitest and the problem is exactly the same ! Only the first change of locale is working...

I was wondering, as some time has passed since this issue was open, whether you had some time to investigate and/or have found what could be the cause of this problem...

Many thanks in advance for keeping us updated on this one.

@ben-hamel
Copy link

I believe the issue is due to Vue Testing Library(VTL). I've submitted an issue on their repo with a repo showing Vue utils working in similar tests - testing-library/vue-testing-library#318

Global translations seem to work in VTL, but local scope definitely has an issue.

@sronveaux
Copy link

Hi @ben-hamel,

Unfortunaly, I also encounter the problem with VTU as I don't use VTL personally.

The way I implemented it on my side was to create an i18n instance with legacy: false and globalInjection: true then assign it to VTU config.global.plugin. That way it is available inside all tested components. (Note that I tried many variations with global translations, local translations, getting the reference with useI18n and always finish with the same problem...)
With this setup, I can change locale as much as I want BUT only in a single test. All the following tests will keep the locale fixed...

The only working way I've found is to recreate a new i18n instance before each test and associate it to global.plugins when mounting the component to test. However this would mean changing calls to mount or shallowMount in every file which is not very clever...

@ben-hamel
Copy link

Yeah, I'm unsure if there's difference due to mine being a Vitest setup. But you can check my repo and see translations are testing correctly with VTU. But with VTL I get the first test translating and then stops afterwards, but only for the local scoped translations.

@morcth
Copy link

morcth commented Sep 1, 2024

I experienced the same with Vue Testing Library.

i18n.global.locale.value = language does not change the value correctly with a .each type test. Vitest.

If the each is the only test run and en in the first language tested, it works if there are 2 languages being tested.

If I run a test before the each test that also accesses locale, then the each will fail.

Was able to make it work with Vue Test Utils.

vue-i18n v9.1.10 works fine by the way. Not sure if that is the latest version that works though.

@sronveaux
Copy link

Hi @kazupon,

Just some words to let you know I investigated a bit deeper in it and found what the problem is. Thanks to @r-kober information, it was quite easy to spot.

The problem happens since #977 was merged and since the effect scope is released when an I18n instance is disposed.
This is only a problem when a global instance is created and reused in multiple tests which is the case in the repos posted in this issue. If a new instance is created in every test, the problem doesn't happen.
I hope this information will be useful to other impacted people here.

Personally, I encountered it as I have a lot of components relying on Vue-I18n so I thought creating a plugin once and for all in the test suite entry point and assigning it to vue-test-utils config would be a good idea:

import { config } from '@vue/test-utils'
const i18nInstance = createI18n({ ... })
config.global.plugins = [i18nInstance]

But doing this, the plugin is re-installed and re-disposed in each unit test. That's why it works only once as the effect scope is destroyed after the first one !

I tried to add a boolean inside the I18nAdditionalOptions to test whether the effect scope should be stopped inside dispose and managed to make everything works as expected !

I'd be happy to open a PR with this if you want, however, I'd like to know what you think about it before writing it:

  • First, I don't have a sufficiently good knowledge of the whole project and all the ways it can be used to know whether this would be a good idea. Sure this can lead to a memory leak but in a user-controlled manner which would theoretically only happen during unit tests.
  • Second, if you think it worths the job to be done, how would you want the boolean to be named ? Something like unitTest to mimick what was done with legacy or something more technical like stopEffectScopeOnDispose which directly tells what it does but is perhaps too verbose ?

Just tell me how you feel about this ! Thanks in advance !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🍰 p2-nice-to-have Priority 2: nothing is broken but it's worth addressing
Projects
None yet
Development

No branches or pull requests

8 participants