Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock the global window object in require.js

  1. I have a web application that uses window.applicationCache for offline access.
  2. All of my code that manages the appCache (eg. checking/updating/swapping the cache) is encapsulated into a "cache-controller" object.
  3. I have unit tests to test my "cache-controller" functions. For testing, I temporarily replace the native window.applicationCache object with my own mock version (since I only want to test my code, not the browsers appCache implementation), eg.

    window.applicationCache = { /* my appCache mock */ };
    // unit tests run here. Code under test references window.applicationCache.
    

A while ago (circa. Chrome 16) this approach worked perfectly. Then Chrome 17, on both Mac & Windows platforms, removed the ability to patch over the browser's default window.applicationCache property (while curiously, it still works fine in Chrome for Linux for all versions up to and including Chrome 26). At the time, I logged a Chromium bug for this; but unfortunately that bug report is still listed as 'unconfirmed'.

Anyway, I've just ported my application from traditional 'browser globals' (ie. loading *.js files via script tags; all JS objects are global) to AMD-style modules, using require.js as the module loader.

One of the benefits of AMD (or CommonJS) is dependency-injection, where your code gets a local reference to any dependent objects, rather than relying on a global reference, eg.

require(['foo'], function(Foo) {
  var bar = new Foo();
});

...which makes it easy to do object mocking, since you can configure the module loader to pass a mock object for 'foo' when in test mode.

I had hoped that by moving to dependency-injection, I could get around my applicationCache issue (as the 'window' reference passed into my modules could be either the global window object, or a mock object).

However I'm not sure how to have require.js inject 'window' as a dependency into my modules?

Is it possible (perhaps using a shim config?) to define a 'window' module; which can then be passed to any code that operates on the global 'window' object? So that I could do something like this:

require(['???'], function(window) {
  // 'window' here is the real window object, or for testing it's a mock window object
  window.applicationCache.update();
});

...where '???' is a module name that refers to the window object.

Or would I need to define my own module that exports 'window', which could mapped differently for unit testing, eg.

// window.js
define(function() {
  return window;  // real global window object
});

// window-mock.js
define(function() {
  return {
    applicationCache: { /* mock version of appCache */ }
  }
});

// for unit testing, remap 'window' to the mock version
require.config({
  map: {
    "cache-controller": {
      "window": "window-mock"
    }
  }
});

// cache-controller.js
require(['window'], function(window) {
  window.applicationCache.update();
});
like image 378
Scott Avatar asked Feb 25 '13 00:02

Scott


People also ask

How do you mock a window object?

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 global objects in Jest?

When mocking global object methods in Jest, the optimal way to do so is using the jest. spyOn() method. It takes the object and name of the method you want to mock, and returns a mock function. The resulting mock function can then be chained to a mocked implementation or a mocked return value.

How do you mock an import Jest?

To mock an imported function with Jest we use the jest. mock() function. jest. mock() is called with one required argument - the import path of the module we're mocking.


1 Answers

I answered my own question. I decided to create the window.js and window-mock.js modules as described above, which allowed me to pass the mock version when running unit tests, and use the 'real' window object when running normally.

like image 197
Scott Avatar answered Dec 09 '22 22:12

Scott