I have a javascript utility file that makes API requests. It has two conditional's at the top that rely on window.VarA and window.VarB. Where VarA and VarB are variables given to the window by our software. If they are set the code inside the conditional is run. Since this file doesn't actually render a window I can't set these properties to anything and get code coverage inside the conditional.
I've attempted rendering a default window but that doesn't seem to work. I have Jest and Enzyme available to me.
The code from the object that I am testing looks like this
let param = "";
let url = "";
if(window.VarA !== underfined){
param = window.VarA; <<--need coverage here
}
if(window.VarB !== underfined){
url = window.VarB; <<--need coverage here
}
Is there some way to mock these window properties for my tests?
To mock the JavaScript window object using Jest, we can use the jest. spyOn method. let windowSpy; beforeEach(() => { windowSpy = jest. spyOn(window, "window", "get"); }); afterEach(() => { windowSpy.
There are two ways to mock functions: Either by creating a mock function to use in test code, or writing a manual mock to override a module dependency.
If you need to mock a global variable for all of your tests, you can use the setupFiles in your Jest config and point it to a file that mocks the necessary variables. This way, you will have the global variable mocked globally for all test suites.
You are right to mock getUsersPage() , but you setting up the mock/spy incorrectly. getUsersPages() is not defined/exported from within canViewPage() . Instead try targeting getUsersPage() directly to create a mock/spy. With the spy working, then you can assert canViewPage('premiumPage') accordingly.
The default test environment for Jest
is a browser-like environment using jsdom
which provides a window
object.
If the test environment is jsdom
then the window
object is accessible as either window
or global
.
Setting variables on window
then becomes as easy as doing the following:
window.VarA = 'foo'; // global.VarA works as well
window.VarB = 'bar'; // global.VarB works as well
The trickier part is getting those variables set before your code runs.
Consider the following config.js
module:
let param = "";
let url = "";
if (window.VarA !== undefined) {
param = window.VarA;
}
if (window.VarB !== undefined) {
url = window.VarB;
}
export const config = {
param,
url
}
If you use require
then the code doesn't run until the module is required, allowing for a test like this:
test('setting window variables', () => {
window.VarA = 'foo'; // global.VarA works as well
window.VarB = 'bar'; // global.VarB works as well
const { config } = require('./config'); // now require the module
expect(config.param).toBe('foo'); // SUCCESS
expect(config.url).toBe('bar'); // SUCCESS
});
On the other hand, if you use import
then the variables need to be defined on window
before the test runs since imports are hoisted and happen before any test code runs:
import { config } from './config'; // this runs first
test('setting window variables', () => {
window.VarA = 'foo'; // <= this doesn't affect config
window.VarB = 'bar'; // <= this doesn't affect config
expect(config.param).toBe('foo'); // FAIL
expect(config.url).toBe('bar'); // FAIL
});
So if you are using import
then you would need to use something like setupFilesAfterEnv
to set the window
variables before your test begins running:
// Configure Jest using setupFilesAfterEnv
// to run a module that sets the window variables
// so they are already set before the test begins...
import { config } from './config';
test('setting window variables', () => {
expect(config.param).toBe('foo'); // SUCCESS
expect(config.url).toBe('bar'); // SUCCESS
});
Great answer by Brian Adams. Just as an alternative to setupFilesAfterEnv
you could also dynamically import module in the body of a test:
test('setting window variables', async () => {
window.VarA = 'foo';
window.VarB = 'bar';
const { config } = await import('./config');
expect(config.param).toBe('foo'); // SUCCESS
expect(config.url).toBe('bar'); // SUCCESS
});
Please note that window
variable cannot be reassigned - further tests will still reference originally assigned value in the first place or produce side effects. For example:
test('setting window variables', async () => { ... });
test('setting a different window variable A', async () => {
window.VarA = 'baz';
const { config } = await import('./config');
expect(config.param).toBe('baz'); // FAIL, it's still 'foo'
});
So to avoid mental confusion it's worth to move window
assignments in beforeAll
or beforeEach
:
beforeAll(() => {
window.VarA = 'foo';
window.VarB = 'bar';
});
test('setting window variables', async () => {
const { config } = await import('./config');
expect(config.param).toBe('foo');
expect(config.url).toBe('bar');
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With