Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I mock a user created window property?

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?

like image 795
Wollzy Avatar asked Feb 06 '19 20:02

Wollzy


People also ask

How do you mock the Windows object in Jest?

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.

How do you mock a function?

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.

How do you mock a variable value in Jest?

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.

How do you mock variables inside a function in Jest?

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.


2 Answers

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
});
like image 63
Brian Adams Avatar answered Oct 22 '22 21:10

Brian Adams


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');   
});
like image 25
Anton Koning Avatar answered Oct 22 '22 22:10

Anton Koning