Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing window.location.assign using Karma/Mocha/Sinon/Chai

I am attempting to unit test a function using Karma as my test runner, Mocha as my testing framework, Sinon as my mocking/stubbing/spying library, and Chai as my assertion library. I am using Chromium as my headless browser in my Karma configuration.

I am totally baffled, however, as to why I am getting the following error:

TypeError: Cannot redefine property: assign

...when I run npm test on this:

function routeToNewPlace() {  
  const newLoc = "/accountcenter/content/ac.html";
  window.location.assign(newLoc);
}
describe('tests', function() {
  before('blah', function() {
    beforeEach('test1', function() {
          window.onbeforeunload = () => '';
      });
    });
  it('routeToNewPlace should route to new place', function() {
    expectedPathname = "/accountcenter/content/ac.html";
    routeToNewPlace();
    const stub = sinon.stub(window.location, 'assign'); 
    assert.equal(true, stub.withArgs(expectedUrl).calledOnce);
    stub.restore();
  });
});

As you can see, I am attempting to assign an empty string to window.location, but this doesn't seem to help.

Here is my karma.config.js:

module.exports = function(config) {
    config.set({
      frameworks: ['mocha', 'chai', 'sinon'],
      files: ['jstests/**/*.js'],
      reporters: ['progress'],
      port: 9876,  // karma web server port
      colors: true,
      logLevel: config.LOG_INFO,
      //browsers: ['Chrome', 'ChromeHeadless', 'MyHeadlessChrome'],
      browsers: ['ChromeHeadless'],
      customLaunchers: {
        MyHeadlessChrome: {
          base: 'ChromeHeadless',
          flags: ['--disable-translate', '--disable-extensions', '--remote-debugging-port=9223']
        }
      },
      autoWatch: false,
      // singleRun: false, // Karma captures browsers, runs the tests and exits
      concurrency: Infinity
    })
  }

Any thoughts would be greatly appreciated.

like image 379
zumafra Avatar asked Aug 29 '18 02:08

zumafra


1 Answers

The problem you are seeing is that window.location.assign is a native function that is non-writable and non-configurable. See the discussion of property descriptors on MDN.

See this screenshot and it may help you understand:

Showing property descriptor of window.location.assing

What this means is that sinon cannot spy on the assign function since it cannot overwrite its property descriptor.

The simplest solution is to wrap all calls to window.location.assign into one of your own methods, like this:

function assignLocation(url) {
  window.location.assign(url);
}

And then in your tests, you can do:

const stub = sinon.stub(window, 'assignLocation');
like image 120
Andrew Eisenberg Avatar answered Sep 20 '22 13:09

Andrew Eisenberg