mattfysh / testr.js

Unit testing require.js modules, with both stubbed and script-loaded dependencies. Compatible with all test frameworks - Jasmine, QUnit, JsTestDriver, Buster JS, etc.
159 stars 7 forks source link

Lazy Loading modules return a string #9

Closed walkandre closed 11 years ago

walkandre commented 11 years ago

I isolated the problem to using require to load modules. After they are loaded the require method returns a string instead of the real module.

Basically:

var module_d = testr('module_d');
module_d.lazyLoad(); // should load the module_anom.js file.
define('module_d', [], function() {
  return {
    'name': 'module_d',
    lazyLoad:function() {
      require(['module_anom'], function(module_anom){
        /**
         * returns a string with the module name instead of the module.
         */
        console.log('module->', module_anom);
      });
    }
  };
});

here's a simple test case: https://dl.dropbox.com/u/869356/testr-modules.zip

mattfysh commented 11 years ago

Hey buddy, thanks for raising this. I'm currently working on an update to intercept the require function (currently only define is intercepted).

Once this is done, you'll be able to lazy load modules. However, I'll need to take a look into how we can stub and mock those modules. Hopefully it's not too much of a ball-buster.

Cheers!

theinterned commented 11 years ago

hey, this is biting me too - I wonder if there is anything I could do to help out?

mattfysh commented 11 years ago

@walkandre @theinterned about to push 1.2.0 of testr.js including lazy loading modules. Currently the module needs to have been pre-defined in a test helper. Would you also like me to add the ability to lazy load the modules asynchronously? I'm not a fan of asynchronous test cases but please let me know if you need this functionality. Cheers!

theinterned commented 11 years ago

Thanks for asking @mattfysh.

I think I could definitely work without asynchronous definition.

One thing I may like to do is redefine the same module several times during my tests. Would I be able to do that (by preloading several helpers I suppose?)

mattfysh commented 11 years ago

Can you not try define('modulename', [deps], factoryFn): ?

mattfysh commented 11 years ago

I think I may have to implement this feature as async-only, to replicate runtime sequencing. For example:

define(function(require) {
  return {
    fn: function() {
      require(['lazyloaded'], function() {
        console.log('A');
      });
      console.log('B');
    }
  };
});

When calling fn():

I've started work on implementing this asynchrously to match real-world sequencing, just remember that your test runner needs to have async test capability.

Also - did the define method work for redefining a module?

Cheers, Matt.

mattfysh commented 11 years ago

testr.js 1.2.0 released with asynchronous lazy loading of modules. Also added the ability to stub these modules.

theinterned commented 11 years ago

@mattfysh I just put together a test: https://gist.github.com/4089669

As I thought, I am not able to redefine a module. Is that what you had in mind?

mattfysh commented 11 years ago

@theinterned not sure what the use case for this would be, can you show me any production code that redefines a module without testr.js. If you're going to completely define a module in your test cases, then it's unlikely that you need to use testr.js to extract the module definition.

theinterned commented 11 years ago

In my case, I have a singleton (which I know is a nono, but I needed some shared state for logged in user etc!) that it would be helpful to be able to redefine for different tests.

theinterned commented 11 years ago

While the test case I presented is re-defining the module within the same test, it would be more likely that different tests would want to define their own mock of the singleton before running...

mattfysh commented 11 years ago

@theinterned that's the most powerful feature of testr.js, already built-in: stubs & mocks.

Given userstate.js:

define(function() {
  return {
    loggedIn: false
  };
});

And another module which depends on the user state singleton, login.js:

define(['userstate'], function(userState) {
  return {
    isLoggedIn: function() {
      return userState.loggedIn;
    }
  };
});

You can then stub/mock the userstate.js module like so, using testr.js:

describe('login module', function() {

  it('returns correct user login state', function() {

    var userStateMock = {
        loggedIn: true
      }, login;

    login = testr('login', {
      'userstate': userStateMock
    });

    expect(login.isLoggedIn()).toBe(true);

  });

});

And there you have it, use the second parameter of the testr.js API to stub or mock dependencies.