1

I've a series of basic tests coded for Intern 1.4 for my code (server and client) developed on the top of Dojo Toolkit 1.9.

Now I want to test classes in isolation, with mock objects instead of the dependencies automatically resolved by the AMD loader.

Here is a set of classes with 'bb' depending on 'aa', with the mock of the 'aa' class, and the test cases I want to verify.

/* file <root>/aa.js */
define([], function() {
    return {
        get: function() { return 'aa' }
    };
});

--

/* file <root>/bb.js */
define([ './aa' ], function(aa) {
    return {
        get: function() { return aa.get() + '-bb' }
    };
});

--

/* file in <root>/tests/aaMock.js */
define([], function() {
    return {
        get: function() { return 'aaMock' }
    };
});

--

/* file in <root>/tests/aaTest.js */
define([ 'intern!object', 'intern/chai!assert', '../bb',  ], function (registerSuite, assert,  bb) {
    registerSuite({
        name: 'testbed',

        'bb untouched': function() {
            assert.strictEqual('aa-bb', bb.get());
        },

        'bb with mocked aa': function () {
            require(
                { map: { '*': { 'aa': '<pkg>/tests/aaMock' } } },
                [ '<pkg>/bb' ],
                function(bb) {
                    assert.strictEqual('aaMock-bb', bb.get());
                }
            );
        }
    });
});

From the test file above, Intern reports one successful test and one failure. As far as I've been able to trace the Dojo loader (Dojo 2 packaged with Intern), the second reference of the 'bb' module comes from the loader cache.

Questions:

  • Is it the right approach? Or should I instrument the 'bb' class with a injectMock() method that will override the local reference of the 'aa' class with a given 'aaMock' reference?
  • I read that RequireJS caches can be invalidated with context and urlArgs flags. Can we do something similar with the Dojo loader?

Note that I did not use the context-sensitive require on purpose as it does not accept a new config.

Thanks, Dom

Dom Derrien
  • 462
  • 2
  • 10
  • 1
    possible duplicate of [How to mock dependencies in Intern tests](http://stackoverflow.com/questions/16324900/how-to-mock-dependencies-in-intern-tests) – C Snover Feb 25 '14 at 16:16
  • Yes, that's a duplicate (don't know how I missed it!). Your mention of the `require.undef` to be shipped with Intern 1.5 is what I'm looking for! Any ETA for this update? – Dom Derrien Feb 26 '14 at 14:56

1 Answers1

2

While waiting for Intern 1.5 and its require.undef feature, I've decided to go with the injectMock() approach:

  • The class to be tested exposes a method injectMock() if has("mockable-api") is true.
  • Only my Intern configuration call has("mockable-api", true);.

There's a little trick:

  • Intern configuration relies on intern/node_modules/dojo/has (as it does not know where my own copy of the Dojo toolkit is);
  • My class relies on the same dependency. If it would rely on dojo/has (the one from my Dojo local copy), it would never get the truthy has("mockable-api");
  • To be able to run the same class in the browser, I've instrumented the dojoConfig definition with a mapping that replaces the dependency on Intern:

    dojoConfig = {
        has: { 'mockable-api': false },
        packages: [{ name: 'dojo', location: '/libs/dojo' }, ... ],
        map: { '*': { 'intern/node_modules/dojo/has': 'dojo/has' } }
    }
    

Now each test case can inject mocks that replace the original dependencies. Then, even tests dealing with the DOM (via dojo/dom or dojo/dom-construct, for example) can work in isolation.

The only weird behavior reported by Intern is related to some circular dependencies identified by the AMD loader, as you can see below with dojo/dom-construct. Hopefully, it does not impact my tests...

Circular dependency: *11 -> tests/allTests -> controllers/tests/mainTest -> controllers/main.js -> dojo/dom-construct -> dojo/dom-attr -> dojo/dom-prop -> dojo/dom-construct

Dom Derrien
  • 462
  • 2
  • 10
  • The circular dependencies in that code are handled correctly by that code, so the warning can be ignored. – C Snover Feb 26 '14 at 16:50