5

I'm having a hard time figuring out how I can access a function that is usually available as a method of the window object in the browser. I'm using Karma, Headless Chrome and Jasmine.

Here is a simplification of my issue:

I have a module called add-numbers-together.js:

function addTogether(a, b) {
    return a + b;
}

(function(){
    addTogether(2,5);
})();

That is being tested by this Jasmine test:

describe('add-numbers-together.js', function() {
    it('Should add numbers together', function() {
        require('module/add-numbers-together');
        console.info(window.addTogether);
    });
});

The require statement is definitely retrieving the module ok, I have tested that.

I was expecting the console.info to print out the definition of the function, as is the case when I do this in an actual browser, but instead this console.info returns undefined. Why is this? and how can I access the addTogether function after the module has been required in the test?

I'm guessing this is some quirk of Jasmine or Headless Chrome but I can't find the answer anywhere no matter how hard I search!

Also, please note: I do not want to add any test code to the module itself, that is not an option for me.

theclarkofben
  • 425
  • 2
  • 6
  • 18

1 Answers1

3

I changed the test slightly to check that the function is not undefined, but it failed regardless of Chrome or ChromeHeadless as the browser.

describe('add-numbers-together.js', function() {
    it('Should add numbers together', function() {
        require('module/add-numbers-together');
        expect(window.addTogether).not.toBeUndefined();
    });
});

To get a version of this test passing, you have several options:

  1. Make the code under test a real module and export the function, then change the test to import that module (recommended). This can also be define and require if using AMD.
  2. Configure your build setup to force a global export from that module without changing the code (webpack can do this, and it's kind of hackey, but it works if you can't edit that script). This is usually only done with 3rd party scripts.
  3. Put the script content in the test file above the test code (not recommended, since you are copy-pasting and changes won't be synced up).
  4. Load the script under test and then the test in the fixture markup (works, but kind of lame since your test fixture HTML now hard codes a script reference).

Here is the code under test rewritten for option #1 with the export of the function.

export function addTogether(a, b) {
    return a + b;
}

(function () {
    addTogether(2, 5);
})();

And here is the test rewritten for option #1 with the import of the module under test.

import * as addNumbersTogether from 'add-numbers-together';

describe('add-numbers-together.js', function () {
    it('Should add numbers together', function () {
        expect(addNumbersTogether.addTogether).not.toBeUndefined();
    });
});
Joe Wilson
  • 5,591
  • 2
  • 27
  • 38
  • Does that work though? my module does not and cannot have the commonjs module.exports() architecture as it is a self executing function that will sit in a script tag on a page. I can't see how I can run the self executing function in the test if I save the module to a variable. – theclarkofben Feb 24 '18 at 15:16
  • If you want to `require` or `import` it, you have to `define` or `export` it OR you can put the module in the page that has the test code and not `require` it. – Joe Wilson Feb 24 '18 at 18:50
  • Ah so if I'm trying to test a self executing function that will live in a script tag on a page then I shouldn't try and require it in the test but should instead just add the script in a script tag in the test fixture? – theclarkofben Feb 25 '18 at 08:51
  • That's all that worked for me when I tried to reproduce your scenario. Either 1) make the file with the self-executing function a real module that exports a function (best way to go), 2) configure your build setup to force a global export from that module without changing the code (webpack can do this, hackey, but works if you can't edit that script), 3) put the script content above the test code (lame, since you are copy-pasting), or 4) load the script under test and then the test in the fixture markup (also lame, since your test fixture hard-codes a script reference). – Joe Wilson Feb 25 '18 at 17:52
  • You've been really helpful. Thank you v much – theclarkofben Feb 26 '18 at 11:27
  • If you add or update your answer to reflect this I will mark it as the correct answer so you get your points – theclarkofben Feb 26 '18 at 11:28