How to mock window/document with mocha/chai

32,751

Solution 1

There are a few options available to you:

Option 1: Use JSDOM

By adding a DOM to your code, you can unit test much of your client-side code within node.js

Option 2: Use MOCHA on the client

Mocha does run inside the client and you can use separate client-side unit tests. This tends to be my preferred approach as I can test against specific browsers and not a specific JS implantation.

Option 3: Use PhantomJS

PhantomJS allows you to control a headless browser within your testing environment.

Option 4: Headless Chrome

Now that Headless Chrome is out, the PhantomJS maintainer has retired.

Solution 2

I have been writing tests similar to what you proposed when I just needed to mock a certain function on window:

it('html test', function () {
    const windowRef = global.window;
    global.window = {document: {querySelector: () => null}};
    const lib = require('lib-that-uses-queryselector');
    assert(true);
    global.window = windowRef;
});

I have been using mock-browser in other tests when I wanted a more complete window object:

it('html test', function () {
     const windowRef = global.window;
     const MockBrowser = require('mock-browser').mocks.MockBrowser;
     global.window = new MockBrowser().getWindow();
     const lib = require('lib-that-uses-window');
     assert(true);
     global.window = windowRef;
});

Note that you probably want to restore the window object (global.window = windowRef; above) after messing with globals.

Share:
32,751
Jeanluca Scaljeri
Author by

Jeanluca Scaljeri

Updated on December 14, 2020

Comments

  • Jeanluca Scaljeri
    Jeanluca Scaljeri over 3 years

    When I try to unit test the getElement function

    class BarFoo {
        getElement() {
            return document.querySelector('#barfoo');
        }
    }
    

    mocha doesn't know anything about document, so I figured that you might do something like this:

    beforeEach(() => {
        global.document = {
            querySelector: () => { ... }
        }
    }
    

    Although this works, I'm wondering if this is the correct approach and maybe there is a package available to solve this issue, because my approach can get laborious if more browser API's are used ?