webpack: Sinon causing issues again

The new version of Sinon is throwing webpack for a loop again. This code:

    function makePublicAPI(require, exports, module) {
        module.exports = sinon;
        sinon.spy = require("./sinon/spy");
        sinon.spyCall = require("./sinon/call");
        sinon.behavior = require("./sinon/behavior");
        sinon.stub = require("./sinon/stub");
        sinon.mock = require("./sinon/mock");
        sinon.collection = require("./sinon/collection");
        sinon.assert = require("./sinon/assert");
        sinon.sandbox = require("./sinon/sandbox");
        sinon.test = require("./sinon/test");
        sinon.testCase = require("./sinon/test_case");
        sinon.match = require("./sinon/match");
    }

    if (isAMD) {
        define(makePublicAPI);
    } else if (isNode) {
        try {
            formatio = require("formatio");
        } catch (e) {}
        makePublicAPI(require, exports, module);         <========
    }

Is causing this warning:

WARNING in ./~/sinon/lib/sinon.js
Critical dependencies:
365:22-29 require function is used in a way, in which dependencies cannot be statically extracted
 @ ./~/sinon/lib/sinon.js 365:22-29

It’s not obvious to me how to work around this. Any of you have any bright ideas?

(the line number indicated in the error, 365, is clearly wrong, and the line with the arrow is actually the offending code)

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Reactions: 2
  • Comments: 51 (15 by maintainers)

Commits related to this issue

Most upvoted comments

It works for me just adding noParse rule on webpack and requiring the dist version instead.

Example:

import sinon from 'sinon/pkg/sinon';

Because of https://github.com/peerigon/legacy-loader/issues/1 I’ve actually switched to using:

npm install --save-dev sinon@next

@dtinth you can also create an alias for sinon

  resolve: {
    alias: {
      sinon: 'sinon/pkg/sinon.js'
    }
  },

then import goes easier 🍵

import sinon from 'sinon';

thanks @graingert , only ur solution with npm install --save-dev sinon@next works for me

@realisation My noParse looks like this:

    noParse: [
      /node_modules\/sinon\//,
    ],

It’s almost like @SpaceK33z’s version but with an added \/ at the end to prevent the rule from matching node_modules/sinon-chai.

Oh hm, Sinon.js is a test framework. I actually spent quite a bit of time writing deadunit, which provides a test API and nice pretty test output for node.js and the browser. It doesn’t have any functionality for creating spies, but that’s ok because using test spies is bad practice

@alexgorbatchev yeah! The alias can also be combined with noParse instead of creating loader and entry.

module: {
  noParse: [
    /\/sinon\.js/,
  ],
}

“works on my machine!” 😆

I’m using:

entry = {
  test: [
    'tests/tests.js',
  ],
}
...
loaders: [
  {
    test: /sinon\/pkg\/sinon\.js/,
    loader: 'legacy!imports?define=>false,require=>false',
  },
]
...
resolve = {
  alias: {
    sinon: 'sinon/pkg/sinon',
  },
}

then you can use:

import sinon from 'sinon';

I found that the solution provided by @solcik and @vitalets was close but raised errors with sinon 1.17.2 and webpack 1.12.9.

Eventually I got it working with

import sinon from 'imports?define=>false,require=>false!sinon/pkg/sinon.js';

when sinon is installed into ./node_modules in the regular way with npm install sinon.

You can clean it up a little by taking advantage of the webpack config:

  module: {
    loaders: [
      { test: /sinon\/pkg\/sinon\.js/, loader: 'imports?define=>false,require=>false' }
    ],
  },

and then

import sinon from 'sinon/pkg/sinon.js';

I bumped into this yesterday. For now I’m using the script-loader to work around this.

@fresheneesz Sinon.js isn’t a test framework, it’s a library to be used in testing. I’m not sure how that stack-overflow question demonstrates spies being a bad practice, it looks more like a conversation about a design that is hard to test.

sinon is our special friend… ^^

If anyone comes here for this error in combination with karma and phantomjs:

PhantomJS 2.1.1 (Linux 0.0.0) ERROR
  ReferenceError: Can't find variable: require

Add Sinon as external in webpack config:

externals: ["sinon"]

(currently webpack 1.x and sinon 2.1.0 for me)

@shults just use sinon@next

FYI sinon@next is very close to release: https://github.com/sinonjs/sinon/issues/966

@heldr +1, works for me,THX

@heldr solution worked =] you are the man!

@vitalets The imports-loader can import multiple symbols at once…

require('imports?this=>window,' +
    'define=>false,' +
    'exports=>false,' +
    'module=>false,' +
    'require=>false!' +
    '../node_modules/sinon/pkg/sinon-1.15.4.js'
);

Thanks @heldr, that seems to work! In my webpack.config.js, I added this:

{
    module: {
        noParse: [
            /node_modules\/sinon/,
        ],
    }
}

I’ll leave this here for others… if you’re depending on libraries for testing that use Sinon, you can’t control what version of Sinon the library uses. So you might run into a problem where the version it uses can’t even be used with script-loader. To deal with this:

  • Download a release version of Sinon, e.g. http://sinonjs.org/releases/sinon-1.14.1.js
  • Turn on noParse for sinon: that means webpack will not parse the file, it won’t be minified, require will not work in the file, etc.
  • Use NormalModuleReplacementPlugin to point require(“sinon”) to your local file instead of the NPM package.

Like so:

module: {
    noParse: [
        /sinon/
    ]
},
plugins: [
    new webpack.NormalModuleReplacementPlugin(/sinon/, __dirname + "/TestRunner/vendor/sinon-1.14.1.js")
]

You should not normally do this because the library you depend on might upgrade to a version of Sinon that isn’t API compatible with your local copy, or you might depend on multiple packages that depend on varying versions of Sinon. This approach is totally circumventing both NPM and webpack. And for sure, NEVER use this approach in releasing code, only tests.

Perhaps once Sinon 2 is more prevalent, these issues will go away, but in the mean time…

You always want to test your interface. If you’re substituting testing your public interface with testing some inner function, I’d say that’s the wrong move, no matter how significant that inner function is. If you have duplication in your tests, you can always take advantage of that symmetry - factor it out into common functions.

I know this is off-topic, but personally I use Grey-box-testing. I know “something” about the implementation, but I don’t really test everything “behind the scenes”.

A common use-case for spies is that you have several functions calling a particular function. By just testing this particular function and by using spies in all other cases I can keep all tests simple and expressive. Otherwise I needed to duplicate all tests.

Testing something “behind the scenes” should be an exception, but sometimes it actually leads to cleaner and more maintainable tests.

Oh dear, I took a look at what it might take to switch it over to UMD and stumbled on this. What on earth? Not sure I’m going to want to tackle that immediately…

Anyone know a good SinonJS alternative? I’ve found the API hard to wrap my head around anyway, with all the extremely similar but not exactly the same functionality.