Reputation: 771
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
Upvotes: 47
Views: 47495
Reputation: 265
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
Upvotes: 3
Reputation: 39
Adding a little bit to Estus Flask's answer, you can also spy on your setup file:
In jest config file activate the setupFiles feature:
setupFiles: ['./test/mock-data/globals.js']
Then inside globals.js spy on the userAgent or any other property:
global.userAgent = jest.spyOn(navigator, 'userAgent', 'get');
Finally in your test mock the return value:
describe('abc', () => {
global.userAgent.mockReturnValue(
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4)\
AppleWebKit/600.1.2 (KHTML, like Gecko)\
Version/13.0.0 Safari/600.1.2'
);
test('123', async () => {
const result = await fnThatCallsOrUseTheUserAgent();
expect(result).toEqual('Something');
});
});
Upvotes: 3
Reputation: 222760
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')
})
...
Upvotes: 74