EzDevInfo.com

Squire.js

Your friendly dependency injector for testing Require.js modules.

Squire.js example with Jasmine and RequireJS

I want to write JS tests. The production code is written with RequireJS. I found a test lib named Squire.js: https://github.com/iammerrick/Squire.js/

From the Squire.js website

Run generates a function that will receive a done callback and execute it after your test function is complete. Particularly useful for frameworks where asynchrony is handled with a callback. Here is an example with Mocha.js. Jasmine can offer this callback approach using Jasmin.Async."

I don't know how to use this with Jasmine async. A small example would be very useful.


Source: (StackOverflow)

How to run code before (or after) each test in karma

I'm looking to use squire.js with karma and want to do a squire.clean() to clean away all the mocks before the next test suite (I'm using jasmine) is run but I cannot see a way to configure karma to run something before (or after) a test suite.

Is there a way?


Source: (StackOverflow)

Advertisements

Squire.js not substituting fake dependency when using store

I'm trying out Squire.js as a dependency loader for RequireJS. Using a totally normal web browser for running unit tests. I want to use store to get a handle to my mocks. But can't stop Squire loading the actual module.

mock works fine:

define(['lib/squire'], function (squire) {
    var injector = new squire();

    injector
    .mock('modules/dependency', {
        run: function () {
            console.log("fake dependency run");
        }
    })
    .require(['modules/module-under-test'], function (module) {
        module.run();
    });
});

Console output

module under test loaded       module-under-test.js:2
module under test run          module-under-test.js:5
fake module run                module-test.js:8

But when I use store like this:

define(['lib/squire'], function (squire) {
    var injector = new squire();

    injector
    .store('modules/dependency')
    .require(['modules/module-under-test', 'mocks'], function (module, mocks) {
        mocks.store["modules/dependency"] = {
            run: function () {
                console.log("fake dependency run");
            }
        };
        module.run();
    });
});

The real one is used and run:

real dependency loaded      dependency.js:2
module under test loaded    module-under-test.js:2
module under test run       module-under-test.js:5
real dependency run         dependency.js:5

Squire says on the front page of the docs that this is ok to do. Using latest version of Squire.js from Github, and also latest RequireJS from requirejs.org. What am I doing wrong?


Source: (StackOverflow)

Jasmine specs not being executed when injecting dependencies with Squire.js

I am attempting to run some Jasmine unit tests for a Backbone view, mocking out dependencies in Squire.

The dependencies of my view are a Baseview, an ICanHaz template and an i18n translation.

I mock out the dependencies after defining Squire and Backbone, and then use a Squire injector to require my view. However, when I run the tests through Grunt, I get the warning message:

Warning: No specs executed, is there a configuration error? Use --force to continue.

Here is my spec:

define(['squire', 'backbone'], function (Squire, Backbone) {
    var injector = new Squire();

    mocks = {
        'views/baseview': function () {
            return Backbone.View.extend({
                grabTemplate: function (options) { }
            });
        },
        'text!templates/menu.htm': '',
        'i18n!nls/menu': {}
    };

    injector.mock(mocks);

    injector.require(['menu'], function (Menu) {

        describe('Menu View', function () {

            it('should be initialisable', function () {
                var menu = new Menu();
                expect(menu).toBeDefined();
            });
        });
    });
});

Does anyone know why my basic unit test is not getting picked up?


Source: (StackOverflow)

Squirejs causing random tests to intermittently fail or not run at all

We're using Karma and Mocha along with Squire for mocking dependencies loaded with RequireJs. Without Squire, our tests run fine however as soon as we initialize a Squire object, everything start breaking:

define(['squire'], function (Squire) {
    var injector = new Squire(); // comment this out and everything works again
});

We found that sometimes Karma reported that no tests were run (even though breakpoints set inside test functions would be hit) and sometimes it would report random errors that shouldn't have been failing. Karma just goes a bit crazy.

How do I use Squire without my tests going crazy?


Source: (StackOverflow)

SquireJS throws error when mocking Backbone.RelationalModel

I am using SquireJS and Mocha to test some code that uses Backbone and Backbone-relational. I am getting the following error when trying to mock an object that contains a Backbone.RelationalModel constructor:

TypeError: this.set is not a function at Backbone.Model (path/to/backbone.js:256:10)

Here is a simplified example of my source code(source.js):

define([ './myObjDependency'], function(myObj){
    return Backbone.RelationalModel.extend({
        relations: [
            {
                type: Backbone.HasOne,
                key: 'myModel',
                relatedModel: myObj.Model
            }
        ]
    });
});

Then in my tests, I have this:

require(['Squire'], function(Squire) {
    var injector = new Squire();
    squire = injector
        .mock("./myObjDependency", {
            Model: Backbone.RelationalModel.extend({})
        });

    squire.require(['./source'], function (src) {
        var srcModelInstance = new src();
        // ... more code here ... //
    });
});

It seems like the Backbone.RelationalModel is calling its parent constructor (Backbone.Model), and is somehow giving it the incorrect this context.

Here is the full stack-trace in case it is helpful:

TypeError: this.set is not a function
at Backbone.Model (/path/to/_bower/components/backbone.js:256:10)
at Backbone.RelationalModel.Backbone.Model.extend.constructor (/path/to/_bower/components/backbone-relational.js:1225:20)
at child [as relatedModel] (/path/to/_bower/components/backbone.js:1566:41)
at Function._.result (/path/to/_bower/components/underscore.js:1168:40)
at Backbone.Relation (/path/to/_bower/components/backbone-relational.js:604:26)
at new child (/path/to/_bower/components/backbone.js:1566:41)
at _.extend.initializeRelation (/path/to/_bower/components/backbone-relational.js:185:15)
at null.<anonymous> (/path/to/_bower/components/backbone-relational.js:1305:31)
at Array.forEach (native)
at Function._.each._.forEach (/path/to/_bower/components/underscore.js:79:11)

Does anyone have any ideas on how to fix this or what the root cause of the problem is? Thanks.


Source: (StackOverflow)

How can I mock RequireJs loader plugin responses in unit tests

The code I'm trying to test relies on RequireJs loader plugins. Example with requirejs/text:

require(['text!templates/foo'], function (data) {
  // handle loaded data
});

For a specific unit test, I'm trying to mock the response for text!templates/foo and override with one relevant for the test:

it('should load a template', function (done) {

  // TODO: mock 'text!templates/foo' here to return 'mock_data'

  // templateViewer uses the text plugin internally to do the actual loading
  templateViewer.templateFor('foo', function (error, templateData) {
    expect(templateData).toEqual('mock_data');
    done();
  });

});

I've looked at RequireJs dependency mock solutions, especially Squire.js but it seems they are all suited for mocking regular dependencies and not plugin responses.

I've also looked at stub libraries like sinon to maybe replace the actual require call but that seems problematic.

What's the recommended practice? I prefer not to replace the entire text plugin with a mock one in my requirejs configuration, just override some of its responses in specific tests.

My setup is node+mocha+requirejs

Edit

Please see this example fiddle project to see my issue with Squire:

http://runnable.com/VUBoI0ex6v9Gs-BJ/squirejs-with-plugins-for-node-js-and-hello-world


Source: (StackOverflow)

Using RequireJS with Mocha and SquireJS on node

I am trying to use RequireJS in node, and found difficulties with path issues.

Here is a simple foo method that returns "foo"

$ cat src/foo.js 

define([], function() {

    var foo = function() {
        return "foo";
    };

    return { foo:foo};
});

Here is bar that requires foo, but it works only when specifying relative path. Is that how it's supposed to be?

$ cat src/bar.js
define(['./foo.js'], function(foo) {

    var bar = function() {
        return foo.foo().replace("foo","bar");
    };

    return { bar : bar };
});

Things get much trickier in the mocha test:

  1. Loading foo and bar requires __dirname workarounds.
  2. The async loading of bar fails (see test 3 and 4).
  3. Importing Squire needs exact path, since it is installed using npm install, but does not conform to the standard node require syntax and does not include the amdefine workaround:

Here is the test code:

$ cat test/footests.js 
var requirejs = require('requirejs');
var chai = requirejs("chai");
var should = chai.should();
var Squire = requirejs(__dirname + "/../node_modules/squirejs/src/Squire.js");

describe('when calling foo.foo()', function () {
   it('should return "foo"', function() {
        var foo = requirejs(__dirname + "/../src/foo.js");
        foo.foo().should.equal("foo");
    });
});

describe('when calling bar.bar()', function () {
    var bar = requirejs(__dirname + "/../src/bar.js");
    it('should return "bar"', function() {
        bar.bar().should.equal("bar");
    });
});

describe('when calling bar.bar() with async requirejs', function () {
    it('should return "bar"', function(done) {
        requirejs(__dirname + "/../src/bar.js", function(bar) {
            bar.bar().should.equal("bar");
            done();
        })
    });
});
describe('when mocking foo.foo() and calling bar.bar()', function () {
    it('should return "barbar"', function(done) {
        var injector = new Squire();
        var fooMock = {
            foo : function() {
                return "foofoo"; /* instead of just foo */
            }
        };
        injector
          .mock('./foo.js', fooMock)
          .require(__dirname + "/../src/bar.js", function(bar) {
              bar.bar().should.equal("barbar");
              done();
          });
    });
});

I've setup a reproduction on github https://github.com/itaifrenkel/node-requirejs-example


Source: (StackOverflow)

SquireJs - Mocking Nested / Conditional Dependencies

Code:

...
if (this.getCurrentRoute() === '') {
  require(['modules/project/project.module', 'modules/topic/topic.module'], function() {
        TopicEditor.navigate('project/new/books/' + bookIds + '/template/' + TopicEditor.config.library.bookTemplateId + '/', {
            trigger: true
        });
  });
}
...

This code is part of the file being tested.

When I run the tests, I get a bunch of 404 errors related to the dependencies of the above modules despite being mocked via injector.mock. I think it has something to do with the asynchronous nature of requirejs. From what I can tell, the require statements are being executed outside of squirejs's context, which means the modules are loading normally.

Has anyone else ever ran into this kind of testing scenario?


Source: (StackOverflow)

How to mock inline requirejs dependencies with squire for unit testing?

I'm using requirejs with inline requires, for instance:

define(['someDep'], function(someDep) {
  return {
    someFn: function() {
      require(['anotherDep'], function(anotherDep) {
        anotherDep.anotherFn();
      });
    }
  } 
});

In my particular case, I cannot include anotherDep in the define.

When testing with mocha, I have a test case like this:

define(['squire'], function(Squire) {
  var squire = new Squire();
  describe('testcase', function() {
    it('should mock anotherDep', function(done) {
      var spy = sinon.spy();
      squire.mock('anotherDep', {
        anotherFn: spy
      });
      squire.require(['someDep'], function(someDep) {
        someDep.someFn();
        expect(spy).to.have.been.calledOnce;
        done();
      });
    });
  });
});

fails because anotherDep calls require directly and not squire.require. The work-around is to replace require in the global scope,

var originalRequire;

before(function() {
  originalRequire = require;
  require = _.bind(squire.require, squire);
});

after(function() {
  require = originalRequire;
});

This works (note that squire.require must be bound to the squire object in some way, I'm using underscore to do this) except that the spy will still not be called because of timing. The test also has to change to

it('should mock anotherDep', function(done) {
  squire.mock('anotherDep', {
    anotherFn: function() {
      done();
    }
  });
  squire.require(['someDep'], function(someDep) {
    someDep.someFn();
  });
});

Is there a better way? If not, hope this provides a solution for others running into the same problem.


Source: (StackOverflow)

Squire is breaking other tests

I'm using Karma, Jasmine, Jasmine.Async, Sinon and Chai.

The good news...this test works correctly. The dependency is mocked, spies get called, and intentionally breaking the test subject results in failed tests.

define(['chai', 'squire'], function (chai, Squire) {

    var should = chai.should(),
        async = new AsyncSpec(this),
        subject, injector = new Squire();

    describe('EventsView', function () {

        describe('when an event is clicked', function () {
            var mockModel, stub;

            async.beforeEach(function (done) {
                setFixtures('<div id="screen"></div>');

                mockModel = {
                    toJSON: function () {
                        return {
                            dimensions: "hu1 vu2",
                            events: [{
                                date: "8/29/2013",
                                id: "8923",
                                title: "Fancy Show",
                                venue: "Lovely venue",
                            }, {
                                date: "8/29/2013",
                                id: "9034",
                                title: "Exciting Game",
                                venue: "Lovely stadium"
                            }],
                            id: 3566,
                            kind: "events",
                            title: "Top events this week"
                        };
                    },
                    fetch: function () {}
                };
                stub = sinon.stub();
                injector.mock('tiles/events-tile/events-detail-model', Squire.Helpers.constructs({
                    fetch: stub
                }));
                injector.require(["tiles/events-tile/events-view"], function (ev) {
                    subject = new ev(mockModel);
                    done();
                });
            });

            async.afterEach(function (done) {
                injector.clean();
                injector.remove();
                done();
            });


            async.it('should attempt to fetch the event details', function (done) {
                $('#screen').html(subject.$el);
                $('.event').first().click();
                stub.called.should.be.true;
                done();
            });
        });
    });
});

The bad news...a shed load of other tests that were previously fine are now failing for weird reasons. For example: Error: Backbone.history has already been started and TypeError: 'undefined' is not an object (evaluating 'Backbone.Validation.mixin')

If I comment out the snippet

injector.require(["tiles/events-tile/events-view"], function (ev) {
  subject = new ev(mockModel);
    done();
});

Then the other tests work again. I've had stuff like this happen before and it has usually been down to a sinon mock not getting restored. The injector.clean() call doesn't seem to be providing the magic bullet I was hoping for.


Source: (StackOverflow)