thlorenz / proxyquireify

browserify >= v2 version of proxyquire. Mocks out browserify's require to allow stubbing out dependencies while testing.
MIT License
151 stars 24 forks source link

ReferenceError: Can't find variable: require #21

Closed mg closed 9 years ago

mg commented 9 years ago

Can't get rid of this error. Here's my package.json:

{
  "name": "",
  "version": "1.0.0",
  "description": "",
  "dependencies": {
  },
  "devDependencies": {
    "karma": "~0.12.25",
    "karma-jasmine": "~0.2.3",
    "karma-phantomjs-launcher": "~0.1.4",
    "karma-junit-reporter": "~0.2.2",
    "jshint-stylish": "~1.0.0",
    "browserify": "~6.3.3",
    "proxyquireify": "~1.1.0",
    "karma-browserify": "~1.0.0"
  }
}

karma.conf.js

module.exports = function(config) {
  config.set({
    basePath : '.',

    autoWatch : false,
    singleRun: true,

    frameworks: ['jasmine', 'browserify'],

    browsers : ['PhantomJS'],

    plugins : [
      'karma-browserify',
      'karma-jasmine',
      'karma-junit-reporter',
      'karma-phantomjs-launcher'
    ],

    preprocessors: {
      '*.spec.js': [ 'browserify' ]
    },

    browserify: {
      debug: true,
      plugin: ['proxyquireify/plugin']
    },

    junitReporter : {
      outputFile: 'test_out/unit.xml',
      suite: 'unit'
    },

    files: ['*.js']
  });
};

hello.js

exports= {
  hello: function() {
    return "hello";
  }
};

hello.spec.js

var proxyquire =  require('proxyquireify')(require);

describe('testing hello', function () {
    var Hello= proxyquire('./hello');

    it('should say hi', function() {
        expect(Hello.hell()).toBe('hello');
    });

});

Output from karma start karma.conf.js --log-level debug

DEBUG [config]: Loading config /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/karma.conf.js
DEBUG [plugin]: Loading plugin karma-browserify.
DEBUG [plugin]: Loading plugin karma-jasmine.
DEBUG [plugin]: Loading plugin karma-junit-reporter.
DEBUG [plugin]: Loading plugin karma-phantomjs-launcher.
DEBUG [framework.browserify]: created browserify bundle: /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify
DEBUG [framework.browserify]: no matching preprocessed file was found, defaulting to prepend
DEBUG [framework.browserify]: add bundle to config.files at position 0
INFO [karma]: Karma v0.12.28 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
DEBUG [temp-dir]: Creating temp dir at /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/karma-5759403
DEBUG [launcher]: /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-phantomjs-launcher/node_modules/phantomjs/lib/phantom/bin/phantomjs /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/karma-5759403/capture.js
DEBUG [watcher]: Excluded file "/Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/karma.conf.js"
DEBUG [framework.browserify]: building bundle
DEBUG [framework.browserify]: adding hello.spec.js to bundle
DEBUG [framework.browserify]: bundling
INFO [framework.browserify]: 19474 bytes written (0.12 seconds)
INFO [framework.browserify]: bundle built
DEBUG [watcher]: Resolved files:
    /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify
    /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/jasmine.js
    /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/boot.js
    /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/adapter.js
    /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/hello.js
    /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/hello.spec.js
DEBUG [web-server]: serving: /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma/static/client.html
DEBUG [web-server]: serving: /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma/static/karma.js
DEBUG [web-server]: upgrade /socket.io/1/websocket/snH5FbsEJtcHVKNbf6AU
DEBUG [karma]: A browser has connected on socket snH5FbsEJtcHVKNbf6AU
INFO [PhantomJS 1.9.8 (Mac OS X)]: Connected on socket snH5FbsEJtcHVKNbf6AU with id 5759403
DEBUG [launcher]: PhantomJS (id 5759403) captured in 2.082 secs
DEBUG [web-server]: serving: /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma/static/context.html
DEBUG [web-server]: serving (cached): /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify
DEBUG [web-server]: serving (cached): /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/jasmine.js
DEBUG [web-server]: serving (cached): /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/hello.spec.js
DEBUG [web-server]: serving (cached): /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/boot.js
DEBUG [web-server]: serving (cached): /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/adapter.js
DEBUG [web-server]: serving (cached): /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/hello.js
PhantomJS 1.9.8 (Mac OS X) ERROR
  ReferenceError: Can't find variable: require
  at /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/hello.spec.js:1

DEBUG [karma]: Run complete, exiting.
DEBUG [launcher]: Disconnecting all browsers
DEBUG [framework.browserify]: cleaning up
DEBUG [launcher]: Process PhantomJS exited with code 0
DEBUG [temp-dir]: Cleaning temp dir /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/karma-5759403

Any ideas? This has been driving my crazy all weekend.

mg commented 9 years ago

Made some chances to karma.conf.js, register the browserify framework first, removed reporting plugin, only include spec file in files and preprocessor:

module.exports = function(karma) {
  karma.set({
    autoWatch : false,
    singleRun: true,

    frameworks: ['browserify', 'jasmine'],

    browsers : ['PhantomJS'],

    plugins : [
      'karma-browserify',
      'karma-jasmine',
      'karma-phantomjs-launcher'
    ],

    files: ['hello.spec.js'],

    preprocessors: {
      'hello.spec.js': [ 'browserify' ]
    },

    browserify: {
      plugin: ['proxyquireify/plugin']
    },

  });
};

Still the same output:

DEBUG [config]: Loading config /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/karma.conf.js
DEBUG [plugin]: Loading plugin karma-browserify.
DEBUG [plugin]: Loading plugin karma-jasmine.
DEBUG [plugin]: Loading plugin karma-phantomjs-launcher.
DEBUG [framework.browserify]: created browserify bundle: /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify
DEBUG [framework.browserify]: add bundle to config.files at position 0
INFO [karma]: Karma v0.12.28 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
DEBUG [temp-dir]: Creating temp dir at /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/karma-24170408
DEBUG [launcher]: /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-phantomjs-launcher/node_modules/phantomjs/lib/phantom/bin/phantomjs /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/karma-24170408/capture.js
DEBUG [framework.browserify]: building bundle
DEBUG [framework.browserify]: adding hello.spec.js to bundle
DEBUG [framework.browserify]: bundling
INFO [framework.browserify]: 7920 bytes written (0.11 seconds)
INFO [framework.browserify]: bundle built
DEBUG [watcher]: Resolved files:
    /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/jasmine.js
    /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/boot.js
    /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/adapter.js
    /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify
    /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/hello.spec.js
DEBUG [web-server]: serving: /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma/static/client.html
DEBUG [web-server]: serving: /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma/static/karma.js
DEBUG [web-server]: upgrade /socket.io/1/websocket/F88RIvgGCOov3ux-QC2z
DEBUG [karma]: A browser has connected on socket F88RIvgGCOov3ux-QC2z
INFO [PhantomJS 1.9.8 (Mac OS X)]: Connected on socket F88RIvgGCOov3ux-QC2z with id 24170408
DEBUG [launcher]: PhantomJS (id 24170408) captured in 2.007 secs
DEBUG [web-server]: serving: /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma/static/context.html
DEBUG [web-server]: serving (cached): /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/jasmine.js
DEBUG [web-server]: serving (cached): /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/boot.js
DEBUG [web-server]: serving (cached): /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/adapter.js
DEBUG [web-server]: serving (cached): /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify
DEBUG [web-server]: serving (cached): /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/hello.spec.js
PhantomJS 1.9.8 (Mac OS X) ERROR
  ReferenceError: Can't find variable: require
  at /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/hello.spec.js:1

DEBUG [karma]: Run complete, exiting.
DEBUG [launcher]: Disconnecting all browsers
DEBUG [framework.browserify]: cleaning up
DEBUG [launcher]: Process PhantomJS exited with code 0
DEBUG [temp-dir]: Cleaning temp dir /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/karma-24170408
thlorenz commented 9 years ago

Could you please push up a repo that reproduces this.

My guess is that karma somehow does something that breaks what proxyquireify is trying to do.

mg commented 9 years ago

Sure! https://github.com/mg/browserifytest

thlorenz commented 9 years ago

Could you please include a script in the package json that allows me to just run it to reproduce your problem? Also please ensure that everything I need is included as a package dependency.

mg commented 9 years ago

npm install karma start karma.conf.js --log-level debug

thlorenz commented 9 years ago

Don't have karma, so needs to be part of the dependency. Please do as I suggested and prep the repo so all we have to do is:

npm install && npm test

Thanks.

mg commented 9 years ago

No problem. npm test works now

mg commented 9 years ago

Some update. Chanced the spec file to only require, not use proxyquerify:

var Hello= require('./hello');
//var proxyquire =  require('proxyquireify')(require);

describe('testing hello', function () {
    //var Hello= proxyquire('./hello');

    it('should say hi', function() {
        expect(Hello.hello()).toBe('hello');
    });

});

Still got the same error. Commented out the proxyquirefy plugin in karma.conf.js:

module.exports = function(karma) {
  karma.set({
    autoWatch : false,
    singleRun: true,

    frameworks: ['browserify', 'jasmine'],

    browsers : ['PhantomJS'],

    plugins : [
      'karma-browserify',
      'karma-jasmine',
      'karma-phantomjs-launcher'
    ],

    files: ['hello.spec.js'],

    preprocessors: {
      'hello.spec.js': [ 'browserify' ]
    },

    browserify: {
      //plugin: ['proxyquireify/plugin']
    },

    logLevel: karma.LOG_DEBUG
  });
};

Now it works, i.ie. the test runs, but of course I can't stub and mock. So the error went away after I removed the proxyquireyf plugin.

mg commented 9 years ago

I've put some console.log entries in the proxyquireify module, specifically at the entry at each of the functions plugin and replacePrelude in replace-prelude.js and outer, findProxyquireifyName, newRequire, req and moduleRequire in prelude.js.

The output is:

~/G/B/S/C/browserifytest (master) npm test

> @1.0.0 test /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest
> ./node_modules/karma/bin/karma start karma.conf.js

in plugin
in replacePrelude
INFO [karma]: Karma v0.12.28 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
in replacePrelude
INFO [framework.browserify]: 11481 bytes written (0.09 seconds)
INFO [framework.browserify]: bundle built
INFO [PhantomJS 1.9.8 (Mac OS X)]: Connected on socket KNhOZTZSGjf9Fs82NCX6 with id 26579723
PhantomJS 1.9.8 (Mac OS X) LOG: 'in outer'

PhantomJS 1.9.8 (Mac OS X) LOG: 'findProxyquireifyName'

PhantomJS 1.9.8 (Mac OS X) LOG: 'in newRequire'

PhantomJS 1.9.8 (Mac OS X) ERROR
  ReferenceError: Can't find variable: require
  at /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/hello.spec.js:1

npm ERR! Test failed.  See above for more details.
npm ERR! not ok code 0
thlorenz commented 9 years ago

Could you try to isolate this by removing karma from the equation? I.e. just use proxyquireify somehow -- don't even have to test anything.

You could also see if you have more luck with zuul.

mg commented 9 years ago

Cant not use karma, since that is the testing solution we use.

But what is there anything in this example that is unusual? Isn't this as plain vanilla combination of karma + browserify + karma-browserify + proxyquireify as it can get? Why isn't everyone using proxyquireify with karma not getting this error? What am I doing that is so unique?

I added https://github.com/bendrucker/proxyquire-universal and registered it as a plugin instead of proxyquireify, failed the same way.

thlorenz commented 9 years ago

Cant not use karma, since that is the testing solution we use.

I'm not saying to not use it ever, just in order to narrow down the problem it would be interesting to take it out of the equation for a second.

elicwhite commented 9 years ago

@mg, I get the exact same error with the same sort of simple setup you have.

@thlorenz it is not trivial to take Karma out of the equation since that is what actually runs the tests.

Without it, we wouldn't be able to run the tests in a browser to attempt to check if that solves it. We would end up needing to wire up PhantomJS, WebkitTestDriver, and others manually which would likely just have other issues. Do you have any recommendations of something we are overlooking?

thlorenz commented 9 years ago

it is not trivial to take Karma out of the equation

It is quite trivial actually, just create a file that uses proxyquireify, browserify it and load the bundle into your browser. Keep in mind that this is not the end solution, just in order to diagnose the problem.

We need to figure out if it's Karma not working together properly here. I haven't seen this problem anywhere without it. It may be doing something that conflicts with proxyquireify and may have to be fixed there, but first we need to narrow down the cause of the problem.

mg commented 9 years ago

hi @thlorenz, I asked the people at karma-browserify and they said, quote:

"Proxyquireify rewrites the bundle prelude such that there's no longer a global require which karma-browserify depends on."

Does that clarify what is going on?

git-jiby-me commented 9 years ago

This is a temporary fix, i made to counter this issue in my gulp based test system,

http://stackoverflow.com/questions/27170117/require-not-defined-when-testing-with-proxyquireify-stubs/27410213#27410213

make it can help solve the issue temporarily until there is a proper fix

elicwhite commented 9 years ago

@git-jiby-me Awesome, I'll give that a try. Just for us to be explicit, that modified line is technically window.request = newRequest, correct?

thlorenz commented 9 years ago

@mg I was suspecting something along those lines.

proxyquireify has to change the prelude in order to inject itself into the require chain. There is no other way to do this that I'm aware of.

I'm unclear why karma depends on a global require. If renaming the require to something else as outlined in the stackoverflow answer above fixes things we could ponder making proyquireify doing this to begin with.

@jhiesey would like to get your input on this.

elicwhite commented 9 years ago

Renaming the require does indeed solve the problem and gives me access to both the original and the new require in my karma tests.

git-jiby-me commented 9 years ago

@TheSavior the modified line is require = newRequire; as global require is already in the scope, so just need to assign to it, no need to do directly in window

mg commented 9 years ago

@git-jiby-me that fix doesn't seem to work for me, blows up with:

PhantomJS 1.9.8 (Mac OS X) testing hello encountered a declaration exception FAILED
    TypeError: 'undefined' is not a function (evaluating 'Error.captureStackTrace(this, ProxyquireifyError)')
        at ProxyquireifyError (/var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify:98:0 <- node_modules/proxyquireify/index.js:5:0)
        at validateArguments (/var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify:117:0 <- node_modules/proxyquireify/index.js:24:0)
        at /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify:159:0 <- node_modules/proxyquireify/index.js:66:0
        at /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify:202:0 <- hello.spec.js:4:0
        at /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/karma-jasmine/lib/boot.js:59
        at /var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify:208:0 <- hello.spec.js:10:0
        at newRequire (/var/folders/qg/r32h5c8s3sb5s4xy6lpthn680000gn/T/9409150f6698b81bf6aaf0b28d56eb7f01704769.browserify:75:0 <- /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/node_modules/proxyquireify/lib/prelude.js:75:0)
        at /Users/magnusorngylfason/Google Drive/Business/Shopping Network/Code/browserifytest/hello.spec.js:1
PhantomJS 1.9.8 (Mac OS X): Executed 1 of 1 (1 FAILED) ERROR (0.015 secs / 0.001 secs)
elicwhite commented 9 years ago

@mg That seems like an unrelated error and is part of your browserified bundle: https://www.google.com/search?q=captureStackTrace+is+not+a+function

mg commented 9 years ago

It turned out that I wasn't sending a stub object with proxyquireify, .e.g.

var Obj= proxyquireify('./obj.js');

Once I added the stub, the error went away. So Im totally down with require=newRequire, happy days, thank you @git-jiby-me

elicwhite commented 9 years ago

Clearly this is working for people right now as is, it just breaks for us using Karma. Has anyone tried using this fix in a non-karma environment?

Dakuan commented 9 years ago

I've bumped into this to. Karma + Browserify + Reactify. @git-jiby-me 's fix worked a charm - although it does make me feel a little uneasy :baby_chick:

bendrucker commented 9 years ago

This should be a relatively easy fix on proxyquireify's end of things. Basically the prelude replacement code needs to check b._expose. If it's empty, require won't be global normally and the replacement doesn't need to be either. If it has any keys, then newRequire needs to be on the window with as b._options.externalRequireName ('require' by default).

If you want details on why karma-browserify exposes your test files, read on:


I'm a maintainer over at karma-browserify and just wanted to weigh in on exactly what's going on here and especially speak to the questions Thorsten raised in https://github.com/thlorenz/proxyquireify/issues/21#issuecomment-66531714. karma-browserify is essentially a collection of hacks that deals with shortcomings in the Karma API and quirks in the Browserify API.

The core issue is that portion of Karma's API that allows for changing the files that it synchronizes with the browser is synchronous. The framework API was designed for things like karma-mocha which just needs to add two static scripts: mocha and some glue between the Mocha API and the Karma browser API. karma-browserify isn't that simple. Generating the bundle is async. The preprocessor API in Karma (e.g. compiling CoffeeScript to JS) is async.

karma-browserify is typically receiving a glob of files that matches multiple test files. Then this is what it does:

  1. Generates a random filename and adds that to Karma's file list (framework)
  2. Begins receiving calls to preprocess your test files (preprocessor)
  3. Adds these files to the random, static bundle file, exposing them as their absolute paths
  4. In place of the actual content, passes 'require(' + path ')' back to Karma

On top of this, it hacks in a preprocessor for the randomized static bundle. This preprocessor is basically there to hold up Karma until the initial bundle has finished. This is why, when in doubt, you design your APIs to be async.

thlorenz commented 9 years ago

Seems like a weird quirk with karma-browserify/karma then. Possibly ask them to fix/remove some of their hacks?

If there is a straightforward solution we could apply to proxyquireify to fix this I'm open to it, but seems like we'd have to fix one hack with another ugly hack.

I'm leaning towards closing this, @bendrucker if you agree go ahead and do so. Thanks.

thlorenz commented 9 years ago

This should be a relatively easy fix on proxyquireify's end of things

If anyone wants to stab at this however I'm open to merging this in (as long as its not too ugly and won't potentially cause problems in other cases).

bendrucker commented 9 years ago

Yeah unfortunately it's a karma thing and karma-browserify is hacky because that's the only way to go.

I just dug in and this is a proxyquireify bug and a one line fix :)

Wait til you see

bendrucker commented 9 years ago

So technically it was a 2 line fix :smile:

My missive about the crazy hoops karma-browserify jumps through above was totally unnecessary. This was just an obscure proxyquireify bug. Commit message describes the issue if anyone cares to take a look for themselves.

Dakuan commented 9 years ago

bad news: Anyone using @git-jiby-me 's patch will find their lives ruined by the v1.2.0 good news: You can just remove the patch entirely and everything will be fine!

bendrucker commented 9 years ago

This is why the advice on the SO post is bad. If you catch a bug in a project and need to hotfix it you should always fork and use a git dep.

thlorenz commented 9 years ago

@Dakuan so removing that patch and using the latest proxyquireify version makes it work with karma for you as well?

Dakuan commented 9 years ago

@thlorenz correct!

thlorenz commented 9 years ago

Ok, I left a comment on the stackoverflow answer.