Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock window.navigator.language using jest

Tags:

I am trying to mock the window.navigator.language attribute in the browser in my jest unit tests so I can test that the content on my page is using the correct language

I have found people online using this:

Object.defineProperty(window.navigator, 'language', {value: 'es', configurable: true});

I have set it right at the top of my test file and it is working there

however, when I redefine in an individual test (and people set to make sure configurable was set to true) it wont redefine it and is just using the old value, does anyone know a way to definitely change it?

beforeEach(() => {     jest.clearAllMocks()     Object.defineProperty(global.navigator, 'language', {value: 'es', configurable: true});     wrapper = shallow(<Component {...props} />) })    it('should do thing 1', () => {       Object.defineProperty(window.navigator, 'language', {value: 'de', configurable: true});       expect(wrapper.state('currentLanguage')).toEqual('de')     })  it('should do thing 2', () => {   Object.defineProperty(window.navigator, 'language', {value: 'pt', configurable: true});   expect(wrapper.state('currentLanguage')).toEqual('pt') }) 

for these tests it is not changing the language to the new language I have set, always using the one at the top

like image 260
the venom Avatar asked Oct 18 '18 07:10

the venom


People also ask

What is the use of jest spyOn?

Jest's spyOn method is used to spy on a method call on an object. It is also very beneficial in cases where the Jest mock module or mock function might not be the best tool for the job on hand. While writing unit tests you only test one particular unit of code, generally a function.

How do I mock a jest file?

To mock any file first step is to tell Jest that you are planning to mock it. After telling Jest that you will be mocking the particular file, you need to tell Jest what it should do, instead of executing the function. You can increase a counter or return a particular value to know that the function was called.


2 Answers

window.navigator and its properties are read-only, this is the reason why Object.defineProperty is needed to set window.navigator.language. It's supposed to work for changing property value multiple times.

The problem is that the component is already instantiated in beforeEach, window.navigator.language changes don't affect it.

Using Object.defineProperty for mocking properties manually will require to store original descriptor and restore it manually as well. This can be done with jest.spyOn. jest.clearAllMocks() wouldn't help for manual spies/mocks, it may be unneeded for Jest spies.

It likely should be:

let languageGetter;  beforeEach(() => {   languageGetter = jest.spyOn(window.navigator, 'language', 'get') })  it('should do thing 1', () => {   languageGetter.mockReturnValue('de')   wrapper = shallow(<Component {...props} />)   expect(wrapper.state('currentLanguage')).toEqual('de') }) ... 
like image 71
Estus Flask Avatar answered Sep 16 '22 13:09

Estus Flask


Alternatively

jest config file

setupFiles: ['./test/mock-data/globals.js'] 

globals.js

const navigator = { language: 'Chalcatongo Mixtec', ...anyOtherPropertiesYouNeed };  Object.defineProperty(window, 'navigator', {    value: navigator,    writable: true }); 

then you can mutate freely in your individual test setup

like image 40
Kyle Treman Avatar answered Sep 19 '22 13:09

Kyle Treman