Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accept locale as configuration #7890

Open
jhnns opened this issue Jul 6, 2020 · 18 comments
Open

Accept locale as configuration #7890

jhnns opened this issue Jul 6, 2020 · 18 comments
Labels
type: feature New feature that does not currently exist

Comments

@jhnns
Copy link
Contributor

jhnns commented Jul 6, 2020

First of all: thank you for your work on Cypress 馃檹. It's awesome and such a pleasure to use!


Current behavior:

I have no unified, platform-independent way of controlling the browser locale. Setting it is specific to the browser and platform and thus error prone.

Desired behavior:

My goal is to get a predictable output of new Intl.DateTimeFormat().resolvedOptions(). I'm on macOS and I haven't found a way to set the browser locale in Chrome. It always resolves to locale: "en-GB" but it should resolve to en-US. I tried setting the LANGUAGE, LANG, LC_ALL environment variables but it seems like they are ignored or overwritten. I also tried the --lang argument but that doesn't work as well (I read that it's only supported on Windows).

I also tried setting

  • launchOptions.preferences.default["settings.language.preferred_languages"]
  • launchOptions.preferences.default["intl.initial_locale"]
  • launchOptions.preferences.localState["variations_safe_seed_locale"]

during 'before:browser:launch' but with no luck.

To be honest, I didn't even get Chrome to start from the command line with the correct locale. I tried it with this command:

LANGUAGE=en-US LANG=en-US LC_ALL=en-US ./"Google Chrome" --user-data-dir="~/temp" --lang="en"

So this is probably also kind of a Chrome issue.

I saw that Cypress is using a dedicated user profile located in ~/Library/Application Support/Cypress/cy/production/browsers/chrome-stable/interactive/Default. Maybe it needs to be set somewhere there...

In this issue I'm asking for two things:

  • In case you know a way how to set the Chrome locale or even in case you know that this is still an unsolved issue, could you please document this in this issue? I think this could be a common problem since a lot of web developers are on macOS.

  • It would be nice if Cypress offered an easy, cross-platform configuration for setting the browser locale. There is a similar request for the timezone and I think this is quite common: you want to control the locale and the timezone your tests are executed with. (Btw: setting the TZ env variable works fine).

Test code to reproduce

Versions

  • cypress@4.9.0
  • macOS@10.15.5
  • Chrome 83.0.4103.116 (Official Build) (64-bit)
@jennifer-shehane
Copy link
Member

Yeah, I'm not sure of a way to set this exactly. Tried a few things as well and was unable to change the locale.

@cypress-bot cypress-bot bot added the stage: proposal 馃挕 No work has been done of this issue label Jul 7, 2020
@jennifer-shehane jennifer-shehane added type: feature New feature that does not currently exist stage: proposal 馃挕 No work has been done of this issue and removed stage: proposal 馃挕 No work has been done of this issue labels Jul 7, 2020
@jhnns
Copy link
Contributor Author

jhnns commented Jul 7, 2020

The Chrome DevTools team recently added the possibility to change this via the "Sensors" tab in the DevTools. They also expose this as experimental API to the Chrome DevTools Protocol. There is:

I was able to set the locale and the timezone in my tests with this snippet:

it("should set the expected locale and timezone", () => {
  return Cypress.automation("remote:debugger:protocol", {
    command: "Emulation.setLocaleOverride",
    params: {
      locale: "de-AT",
    },
  })
    .then(() => {
      return Cypress.automation("remote:debugger:protocol", {
        command: "Emulation.setTimezoneOverride",
        params: {
          timezoneId: "Pacific/Fiji",
        },
      });
    })
    .then(() => {
      const { locale, timeZone } = new Intl.DateTimeFormat().resolvedOptions();

      console.log(locale, timeZone); // Logs 'de-AT' and 'Pacific/Fiji'
    });
});

Working example: https://github.com/jhnns/cypress-test-tiny/blob/locale-fix/cypress/integration/spec.js

So this is a nice workaround. But it seems like Cypress.automation("remote:debugger:protocol" is an internal API since it's not officially documented. It would be awesome if I could either configure it via the cypress.json or even change it on runtime by calling a command.

@jennifer-shehane
Copy link
Member

Yeah, passing things to the Chrome DevTools Protocol is not officially documented. I'm going to check with the team on what our plans were for exposing/documenting this because I've seen some other people tap into it as well.

Will leave this issue open for a more easily configurable way to set locale.

@cedric-matheus
Copy link

cedric-matheus commented Nov 11, 2020

Hello friends!

The Chrome DevTools team recently added the possibility to change this via the "Sensors" tab in the DevTools. They also expose this as experimental API to the Chrome DevTools Protocol. There is:

I was able to set the locale and the timezone in my tests with this snippet:

it("should set the expected locale and timezone", () => {
  return Cypress.automation("remote:debugger:protocol", {
    command: "Emulation.setLocaleOverride",
    params: {
      locale: "de-AT",
    },
  })
    .then(() => {
      return Cypress.automation("remote:debugger:protocol", {
        command: "Emulation.setTimezoneOverride",
        params: {
          timezoneId: "Pacific/Fiji",
        },
      });
    })
    .then(() => {
      const { locale, timeZone } = new Intl.DateTimeFormat().resolvedOptions();

      console.log(locale, timeZone); // Logs 'de-AT' and 'Pacific/Fiji'
    });
});

Working example: https://github.com/jhnns/cypress-test-tiny/blob/locale-fix/cypress/integration/spec.js

So this is a nice workaround. But it seems like Cypress.automation("remote:debugger:protocol" is an internal API since it's not officially documented. It would be awesome if I could either configure it via the cypress.json or even change it on runtime by calling a command.

This solution dont work for me =/

This is my solution for the problem, enjoy!

describe('Detect browser language', () => {
  it('when browser language is english', () => {
    cy.visit('http://localhost:3000', {
      onBeforeLoad(win) { // solution is here
        Object.defineProperty(win.navigator, 'languages', {
          value: ['en-US'],
        });
      },
    });

    cy.contains('Welcome to react using react-i18next');
  });

  it('when browser language is german', () => {
    cy.visit('http://localhost:3000', {
      onBeforeLoad(win) { // solution is here
        Object.defineProperty(win.navigator, 'languages', {
          value: ['de-DE'],
        });
      },
    });

    cy.contains('Willkommen, um mit react-i18next zu reagieren');
  });
});

@pmgmendes
Copy link

pmgmendes commented Apr 22, 2021

Hey!
Had the same issue. The 2nd approach described by Lukas at http://www.lukasjakob.com/how-to-set-browser-default-language-in-cypress worked for me.

// cypress/plugins/index.js

on('before:browser:launch', (browser, launchOptions) => {
  if (browser.name === 'chrome') {
    launchOptions.args.push('--lang=en-GB');
    return launchOptions;
  }
});

Note that different arguments will apply when running the tests in a browser other than Chrome.

EDIT

Actually the approach doesn't work when running the tests with one of Cypress Docker images. For that I had to rely in @jhnns solution based on Chrome DevTools Protocol.

// cypress/support/index.js

Cypress.on('test:before:run', () => {
  Cypress.automation('remote:debugger:protocol', {
    command: 'Emulation.setLocaleOverride',
    params: {
      locale: 'en-GB'
    }
  });
});

@syuilo
Copy link

syuilo commented Oct 28, 2021

I could not get any of the solutions to work. My application is i18n and the message displayed on the screen is different depending on the user's language (set in the browser). Unfortunately, when I run the test on my local machine and when I run it on GitHub Actions, the browser language seems to be different and I don't get consistent test results. (To make the tests pass successfully, you need to specify the messages in all languages with regular expressions).
Hope this can be resolved.

@moekify
Copy link

moekify commented Mar 4, 2022

I think this would be really interesting as a way to test i18n or anything locale changing to work as expected.

@cypress-bot cypress-bot bot added stage: backlog and removed stage: proposal 馃挕 No work has been done of this issue labels Apr 29, 2022
@RiZKiT
Copy link

RiZKiT commented Apr 29, 2022

@syuilo at least for i18n texts we generate json files from message properties via properties-reader npm package and then use a helper function which first aggregates all json files and then returns the message string in the requested language. The code is a bit longer than 3 lines and not open source, that's why I'm not pasting it here right now.

@barbaracabralbr
Copy link

barbaracabralbr commented Aug 24, 2022

Any news about this issue? An additional information is that on my html the argument <html lang="eng"> is not being set so I think cypress browser is getting the locale from my OS.

@mauriciabad
Copy link

This issue is very annoying for me, because my laptop is in en-GB and my CI runtime uses en-US, but my code supports en (both).
So when I test the code in my laptop the dates have a different format than I the CI, and making the test impossible to pass in both.

Plis, add a way to configure navigator.locale or make sure it's the same always.

@murilomorato
Copy link

I have been suffering from this problem too. To use it in CI, I had to make big changes in the project, setting the language every time I needed to use cy.visit()... It got really bad.

@nanu-c
Copy link

nanu-c commented Dec 9, 2022

For us, this is also a problem, because we have keycloak as login provider and it's not easy to change the language there.

@verheyenkoen
Copy link
Contributor

+1!

Was using Intl.DateTimeFormat which worked perfectly with cypress run and cypress open but not in docker. I was also doing some PDF parsing so I assumed it was a dependency problem in the container and jumpt in a very deep hole, but it just turned out to be the default locale being different. I guess Cypress should ideally do what servers do, also in terms of setting the locale to "en-us".

@FerrazLeandro
Copy link

Ei! Teve o mesmo problema. A segunda abordagem descrita por Lukas em http://www.lukasjakob.com/how-to-set-browser-default-language-in-cypress funcionou para mim.

// cypress/plugins/index.js

on('before:browser:launch', (browser, launchOptions) => {
  if (browser.name === 'chrome') {
    launchOptions.args.push('--lang=en-GB');
    return launchOptions;
  }
});

Observe que argumentos diferentes ser茫o aplicados ao executar os testes em um navegador diferente do Chrome.

EDITAR

Na verdade, a abordagem n茫o funciona ao executar os testes com uma das imagens do Cypress Docker. Para isso eu tive que confiar em@jhnnssolu莽茫o baseada no protocolo Chrome DevTools.

// cypress/support/index.js

Cypress.on('test:before:run', () => {
  Cypress.automation('remote:debugger:protocol', {
    command: 'Emulation.setLocaleOverride',
    params: {
      locale: 'en-GB'
    }
  });
});

Estou utilizando docker no gitlab e n茫o funcionou aqui :(

@goska-malaga
Copy link

It is disappointing that after over 3 years there seems to be no option to have same test passing on github and on local.
I was quite surprise to see Assertion Error on CI expected to have value '01/08/2023', but the value was '1/8/2023'
and it took me a moment to notice it is not just missing "0" but that it is US date format.
Unfortunately while I learned how to open devtools from config I didn't manage to change locale setting (macOS) the only thing that works is to open preferences and delete UK (doing that each time when I open cypress is not fun).
And if I get it right from comments using docker image doesn't help either?

@goska-malaga
Copy link

After I figured out that what I test is an iframe so might behave differently then the complete website I run some more tests and now I cannot get my head around:
Edge - default setting US
Chrome - default setting UK
(that is different in both cases with Cypress then I have when I open the browser itself)
opening google.com - Polish
opening bing.com - English with exception it knows that I am Polish
opening disneyplus.com - it tries to open lang en-pl (since it fails it opens English)
How can we reliably test?
I am quite surprised this doesn't get more complaints
and I am not sure if I should complain that once I change the lang browser setting in browser open by Cypress it will remember it for next time, which I would expect shouldn't happen with what suppose to be inprivate browsing

@timtos
Copy link

timtos commented Nov 22, 2023

Any updates here?

@fluidsonic
Copy link

It got even more weird recently and we don't know what triggered it.

As per MDN, it's perfectly fine to do the following to format according to the user's preferred language/locale order:

const date = new Date("2012-05-24");
const formattedDate = new Intl.DateTimeFormat(navigator.languages).format(date);

That now causes the following error in the page tested with Cypress.

RangeError: Incorrect locale information provided

Node 20.13.1, Cypress 13.9.0, Browser Electron 118 (headless)
Fails with the above error on GitHub Actions but not locally (macOS).

The reason is that navigator.languages returns ["en-US"] locally (macOS) but ["en-US", "c"] on GitHub Actions. And c is not a valid locale for the Intl API.

It works when removing "c":

const locales = navigator.languages.filter(it => it.toLowerCase() !== 'c')
const date = new Date("2012-05-24");
const formattedDate = new Intl.DateTimeFormat(locales).format(date);

While investigating that strange bug I concluded that I should probably set a consistent browser locale somewhere for Cypress testing. But after finding this issue it looks like that's not yet possible :/

Manually overwriting navigator properties is certainly one (potentially unreliable) way to add some consistency. But it won't affect the Intl API and also not the various locale-sensitive functions provided by the browser.

TL;DR: We need some consistency regarding locales to test properly :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: feature New feature that does not currently exist
Projects
None yet
Development

No branches or pull requests