Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiversion support for child require() calls in r.js #726

Closed
mccormicka opened this issue Apr 26, 2013 · 3 comments
Closed

Multiversion support for child require() calls in r.js #726

mccormicka opened this issue Apr 26, 2013 · 3 comments

Comments

@mccormicka
Copy link

I have been trying to use multiversion suport in order to support unit testing of my require modules in node. Which works fine for the top level require() calls but not for nested require calls as they use the defaultContext instead.

For example if I create a default context that looks like this.

var originalContext = {
     path:{
        database: 'realdatabase'
    }
};

require.context(originalContext);

I then setup a bootstrap a realdatabase and a fakedatabase file

//Bootstrap.js
define(function(){
    var db = require('database');
});

//RealDatabase.js
define(function(){
    console.log('real database created');
});

//FakeDatabase.js
define(function(){
    console.log('fake database created');
});

Now if i setup my test as follows.

//Create a new context to run the tests in replacing any real 
//modules with the supplied stubs.
function createContext(stub){
    var alteredConfig = _.clone(originalContext);

    //Need a unique name for each test run.
    alteredConfig.context = Math.floor(Math.random() * 1000000);
    alteredConfig.map = {
        '*': stubs
    };

    var context = require.config(alteredConfig);
    console.log("Created context with contextName", alteredConfig.context);
    return context;
}

//Stub for our database.
var stubs = {
    database: 'fakedatabase'
};

var context = createContext(stubs);
//traces Created context with contextName 123343434 (randome number);

context(['require', 'database'], function (require, database) {
     //traces fake database created
     // so the context has injected our fake database correctly 
    // as our database.

    var fakeTest = require('database');
     //traces fake database created
     // so the context has injected our fake database correctly 
    // as the fakeTest.

    var bootstrap = require('bootstrap');
    //traces real database created.
   //So the context has reverted to using the default '_' 
   //context for injection when calling require() from within child modules.
});

Is there any way to make require and r.js use the newly created context throughout the chain of requires? so parent->child->child all using the some context instead of revering to the default context for child require() calls.

Thanks

@mccormicka
Copy link
Author

Ok I sort of have this working by making sure that all my modules have a reference to the localContext as in

define(function(require){
    var db = require('database');
});

Along with some monkey patching to the r.js file.
lines 1904..

req = requirejs = function (deps, callback, errback, optional, contextName) {
    contextName = contextName || defContextName;
    //Find the right context, use default
    var context, config;

line 2398

if(!context.defined[moduleName]){
    require([moduleName], null, null, null, context.contextName);
}

I need to work out how to run the unit tests to see if my changes break anything. But this works it passes the current context along with the localRequire call. therefore the chaining of the context to its children then works.

@mccormicka
Copy link
Author

Added pull request to r.js
requirejs/r.js#436

@jrburke
Copy link
Member

jrburke commented May 7, 2013

The require passed to define()'d modules when specified like this:

define(function(require){
    var db = require('database');
});

will be the local require, specific to the context. Note that if require is not specified as an argument in the function passed to define(), that will be a problem, so be sure that is there.

Also, for any top level calls, the example mentioned using context(['require', 'database'], function (require, database) {, I would instead use context directly:

context(['database'], function (database) {
  var bootstrap = context('bootstrap');
});

With that, it should all be using local, context-specific require calls. If not, it would be good to know what part fails.

So I think this is already possible today, so closing for now, but if further discussion identifies a bug we can reopen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants