cjohansen/Sinon.JS — pull request #523 by neonstalwart (2014-07-31 19:06:16+00:00)
Title: loading via AMD can break

the way in which sinon is trying to load via AMD is prone to breaking - particularly when the 'A' (asynchronous) in AMD comes into play.

i was randomly seeing issues where the following line was throwing an error because `returns` was not a function:

```js
var fn = sinon.stub().returns(value);
```

i started digging into the way sinon is loaded with AMD and i'm fairly sure there are multiple possible race conditions that could occur which could cause sinon to fail. i haven't done an exhaustive search but i'll share the 2 i was able to find after spending a few minutes inspecting the code. for reference, i'm looking at v1.10.3 (https://github.com/cjohansen/Sinon.JS/blob/v1.10.3/lib/sinon.js#L341-L354)

1. https://github.com/cjohansen/Sinon.JS/blob/v1.10.3/lib/sinon/spy.js#L409 is executed as soon as the script for spy.js has been injected. at that time, there is no guarantee that `sinon.spyCall` has been defined - call.js may not have arrived/executed by that time. fortunately, at least within sinon itself, it looks like everything refers to `sinon.spyCall` rather than `sinon.spy.spyCall`. maybe that line can be removed? alternatively, move the spy.spyCall assignment into sinon.js

```js
sinon.spyCall = sinon.spy.spyCall = require('./sinon/call');
```

1. https://github.com/cjohansen/Sinon.JS/blob/v1.10.3/lib/sinon/stub.js#L135-L149 is executed as soon as the script for stub.js has been injected. at that time, there is no guarantee that `sinon.behavior` has been defined - behavior.js may not have arrived/executed by the time the stub.js code is executed. this is in fact the issue i'm seeing.

i stopped looking at this point because i found what i was looking for but i would not be surprised to find more. a quick way to find more of these would be to look at each file and see what `sinon.*` properties it references in the path of code which is executed immediately when that script is loaded and if the property is not one of the ones defined in lib/sinon.js then those references will randomly fail due to the asynchronous nature of AMD.