pax_global_header00006660000000000000000000000064127677551130014530gustar00rootroot0000000000000052 comment=4eaad42f0715face6b53899fad7bcbc49d079417 sinon-4eaad42f0715face6b53899fad7bcbc49d079417/000077500000000000000000000000001276775511300201115ustar00rootroot00000000000000sinon-4eaad42f0715face6b53899fad7bcbc49d079417/.editorconfig000066400000000000000000000005761276775511300225760ustar00rootroot00000000000000; EditorConfig file: http://EditorConfig.org ; Install the "EditorConfig" plugin into your editor to use root = true [*] charset = utf-8 end_of_line = lf insert_final_newline = true indent_style = space indent_size = 4 trim_trailing_whitespace = true # Matches the exact files either package.json or .travis.yml [{package.json, .travis.yml}] indent_style = space indent_size = 2 sinon-4eaad42f0715face6b53899fad7bcbc49d079417/.eslintignore000066400000000000000000000000171276775511300226120ustar00rootroot00000000000000coverage/ pkg/ sinon-4eaad42f0715face6b53899fad7bcbc49d079417/.eslintrc000066400000000000000000000137541276775511300217470ustar00rootroot00000000000000{ "ecmaFeatures": {}, "env": { "browser": true, "node": true, "amd": true }, "rules": { "no-alert": 2, "no-array-constructor": 2, "no-bitwise": 2, "no-caller": 2, "no-catch-shadow": 2, "no-comma-dangle": 2, "no-cond-assign": 2, "no-console": 2, "no-constant-condition": 2, "no-continue": 2, "no-control-regex": 2, "no-debugger": 2, "no-delete-var": 2, "no-div-regex": 0, "no-dupe-keys": 2, "no-dupe-args": 2, "no-duplicate-case": 2, "no-else-return": 2, "no-empty": 2, "no-empty-character-class": 2, "no-empty-label": 2, "no-eq-null": 0, "no-eval": 2, "no-ex-assign": 2, "no-extend-native": 2, "no-extra-bind": 2, "no-extra-boolean-cast": 2, "no-extra-parens": 0, "no-extra-semi": 2, "no-extra-strict": 2, "no-fallthrough": 2, "no-floating-decimal": 0, "no-func-assign": 2, "no-implied-eval": 2, "no-inline-comments": 0, "no-inner-declarations": [2, "functions"], "no-invalid-regexp": 2, "no-irregular-whitespace": 2, "no-iterator": 2, "no-label-var": 2, "no-labels": 2, "no-lone-blocks": 2, "no-lonely-if": 0, "no-loop-func": 2, "no-mixed-requires": [0, false], "no-mixed-spaces-and-tabs": [2, false], "linebreak-style": [0, "unix"], "no-multi-spaces": 2, "no-multi-str": 2, "no-multiple-empty-lines": [2, {"max": 2}], "no-native-reassign": 2, "no-negated-in-lhs": 2, "no-nested-ternary": 2, "no-new": 2, "no-new-func": 2, "no-new-object": 2, "no-new-require": 0, "no-new-wrappers": 2, "no-obj-calls": 2, "no-octal": 2, "no-octal-escape": 2, "no-param-reassign": 0, "no-path-concat": 0, "no-plusplus": 0, "no-process-env": 0, "no-process-exit": 2, "no-proto": 2, "no-redeclare": 2, "no-regex-spaces": 2, "no-reserved-keys": 0, "no-restricted-modules": 0, "no-return-assign": 2, "no-script-url": 2, "no-self-compare": 0, "no-sequences": 2, "no-shadow": 2, "no-shadow-restricted-names": 2, "no-space-before-semi": 0, "no-spaced-func": 2, "no-sparse-arrays": 2, "no-sync": 0, "no-ternary": 0, "no-trailing-spaces": 2, "no-this-before-super": 0, "no-throw-literal": 0, "no-undef": 2, "no-undef-init": 2, "no-undefined": 0, "no-unexpected-multiline": 0, "no-underscore-dangle": 2, "no-unneeded-ternary": 0, "no-unreachable": 2, "no-unused-expressions": 2, "no-unused-vars": [2, {"vars": "all", "args": "after-used"}], "no-use-before-define": 2, "no-void": 0, "no-var": 0, "prefer-const": 0, "no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }], "no-with": 2, "no-wrap-func": 2, "array-bracket-spacing": [2, "never"], "accessor-pairs": 2, "block-scoped-var": 0, "brace-style": [0, "1tbs"], "callback-return": 0, "camelcase": 2, "comma-dangle": [2, "never"], "comma-spacing": 2, "comma-style": 2, "complexity": [0, 11], "computed-property-spacing": [0, "never"], "consistent-return": 2, "consistent-this": [0, "that"], "constructor-super": 0, "curly": [2, "all"], "default-case": 1, "dot-location": 0, "dot-notation": [2, { "allowKeywords": true }], "eol-last": 2, "eqeqeq": 2, "func-names": 0, "func-style": [0, "declaration"], "generator-star": 0, "generator-star-spacing": 0, "global-strict": [2, "never"], "guard-for-in": 2, "handle-callback-err": 0, "indent": [2, 4, {"indentSwitchCase": true}], "init-declarations": 0, "key-spacing": [2, { "beforeColon": false, "afterColon": true }], "lines-around-comment": 0, "max-depth": [0, 4], "max-len": [2, 120, 4], "max-nested-callbacks": [1, 2], "max-params": [0, 3], "max-statements": [0, 10], "new-cap": 2, "new-parens": 2, "newline-after-var": 0, "object-curly-spacing": [0, "never"], "object-shorthand": 0, "one-var": [2, { // Exactly one declaration for uninitialized variables per function (var) or block (let or const) "uninitialized": "always", // Exactly one declarator per initialized variable declaration per function (var) or block (let or const) "initialized": "never" }], "operator-assignment": [0, "always"], "operator-linebreak": 0, "padded-blocks": 0, "quote-props": 0, "quotes": [2, "double"], "radix": 0, "require-yield": 0, "semi": 2, "semi-spacing": [2, {"before": false, "after": true}], "sort-vars": 0, "space-after-function-name": [2, "never"], "space-after-keywords": [2, "always"], "space-before-blocks": [2, "always"], "space-before-function-paren": [2, {"anonymous": "always", "named": "never"}], "space-before-function-parentheses": [0, "always"], "space-in-brackets": [0, "never"], "space-in-parens": [0, "never"], "space-infix-ops": 2, "space-return-throw-case": 2, "space-unary-ops": [2, { "words": true, "nonwords": false }], "spaced-comment": 0, "spaced-line-comment": [0, "always"], "strict": 2, "use-isnan": 2, "valid-jsdoc": 0, "valid-typeof": 2, "vars-on-top": 0, "wrap-iife": 0, "wrap-regex": 0, "yoda": [2, "never"] } } sinon-4eaad42f0715face6b53899fad7bcbc49d079417/.gitignore000066400000000000000000000000331276775511300220750ustar00rootroot00000000000000pkg node_modules coverage/ sinon-4eaad42f0715face6b53899fad7bcbc49d079417/.jscsrc000066400000000000000000000004721276775511300214040ustar00rootroot00000000000000// should allow comments in this type of config { "excludeFiles": [ "coverage", "node_modules/**", "build/*", "coverage/*", "pkg/*" ], "preset": "crockford", // Sinon specific overrides "validateQuoteMarks" : "\"", "requireMultipleVarDecl" : null } sinon-4eaad42f0715face6b53899fad7bcbc49d079417/.travis.yml000066400000000000000000000013441276775511300222240ustar00rootroot00000000000000language: node_js node_js: - "0.12" - "4.4" sudo: false before_install: - npm config set strict-ssl false # Workaround for intermittent build failures # install buster separately from `npm install`, as it uses the C compiler, which might cause the # npm ERR! cb() never called! # errror to appear, causing the builds to fail # # See this discussion: https://github.com/npm/npm/issues/7014 - npm install buster@0.7.18 before_script: - rvm install 2.2.0 - rvm use 2.2.0 --default - gem install juicer # we only need to run eslint once per build, so let's conserve a few resources - 'if [ "x$TRAVIS_NODE_VERSION" = "x0.12" ]; then $(npm bin)/eslint .; fi' script: - ./scripts/ci-test.sh git: depth: 10 sinon-4eaad42f0715face6b53899fad7bcbc49d079417/AUTHORS000066400000000000000000000131171276775511300211640ustar00rootroot00000000000000Christian Johansen Morgan Roderick Maximilian Antoni ben hockey Carl-Erik Kopseng Phred Tim Fischbach Tim Ruffles Jonathan Sokolowski Domenic Denicola Tim Perry Andreas Lind William Sears Felix Geisendörfer Bryan Donovan kpdecker Keith Cirkel Luis Cardoso Tobias Ebnöther Cory Martin Sander Andrew Gurinovich Tristan Koch Konrad Holowinski Benjamin Coe Travis Kaufman Marten Lienen ben fleis Garrick Cheung Gavin Huang zcicala Jonny Reeves Tamas Szebeni August Lilleaas Cormac Flynn Duncan Beevers Garrick Glen Mailer Jason Miller Jmeas Ming Liu Robin Pedersen Roman Potashow Scott Andrews Soutaro Matsumoto Thomas Meyer geries Satoshi Nakamura Alexander Schmidt Jason Karns Victor Costan Brandon Heyer Marcus Hüsgen Márton Salomváry Jonathan Freeman Simen Bekkhus Alex Urbano Irina Dumitrascu yoshimura-toshihide Spencer Elliott Devin Weaver なつき Martin Hansen gtothesquare Patrick van Vuuren Matt Kern Jeffrey Falgout G.Serebryanskyi mohayonao Max Calabrese Farid Neshat James Barwell Henry Tung vitalets Josh Graham Michael Jackson Mikolaj Banasik stevesouth Mustafa Sak Nicholas Stephan Nikita Litvin Niklas Andreasson Olmo Maldonado Paul Carduner Blake Israel Rajeesh C V Raynos Robert Hurst till Rodion Vynnychenko Ryan Wholey wwalser Sergio Cinos Shawn Krisman Shinnosuke Watanabe Simone Fonda Gyandeep Singh Søren Enemærke TEHEK Firefox AJ Ortega Tek Nynja Tim Branyen Blake Embrey Blaine Bublitz Antonio D'Ettole Timo Tijhof Ali Shakiba Alfonso Boza Volkan Ozcelik Will Butler William Meleyal Alexander Aivars Xiao Ma Alex Kessaris charlierudolph clint goligo hashchange jamestalmage kbackowski Adrian Phinney Gavin Boulton Gilad Peleg Giorgos Giannoutsos ngryman Gord Tanner Gordon L. Hempton Sven Fuchs Harry Wolff Ian Lewis Ian Thomas James Beavers Jan Kopriva Jan Suchý Jason Anderson Adam Hull simonzack John Bernardo Eric Wendelin Eli White Jordan Hawker Joscha Feth Joseph Spens Dmitriy Kubyshkin Kevin Turner Kim Joar Bekkelund Kris Kowal Kurt Ruppel Lars Thorup Luchs Daryl Lau Marco Ramirez Mario Pareja Martin Brochhaus Burak Yiğit Kaya Max Klymyshyn Brian M Hunt sinon-4eaad42f0715face6b53899fad7bcbc49d079417/CONTRIBUTING.md000066400000000000000000000123641276775511300223500ustar00rootroot00000000000000# Contributing to Sinon.JS There are several ways of contributing to Sinon.JS * Help [improve the documentation](https://github.com/sinonjs/sinon-docs) published at [the Sinon.JS website](http://sinonjs.org) * Help someone understand and use Sinon.JS on the [the mailing list](http://groups.google.com/group/sinonjs) * Report an issue, please read instructions below * Help with triaging the [issues](http://github.com/cjohansen/Sinon.JS/issues). The clearer they are, the more likely they are to be fixed soon. * Contribute to the code base. ## Reporting an issue To save everyone time and make it much more likely for your issue to be understood, worked on and resolved quickly, it would help if you're mindful of [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) when pressing the "Submit new issue" button. As a minimum, please report the following: * Which environment are you using? Browser? Node? Which version(s)? * Which version of SinonJS? * How are you loading SinonJS? * What other libraries are you using? * What you expected to happen * What actually happens * Describe **with code** how to reproduce the faulty behaviour ### Bug report template Here's a template for a bug report > Sinon version : > Environment : > Example URL : > > ##### Bug description Here's an example use of the template > Sinon version : 1.10.3 > Environment : OSX Chrome 37.0.2062.94 > Example URL : http://jsbin.com/iyebiWI/8/edit > > ##### Bug description > > If `respondWith` called with a URL including query parameter and a function , it doesn't work. > This error reported in console. > ``` > `TypeError: requestUrl.match(...) is null` > ``` ## Contributing to the code base Pick [an issue](http://github.com/cjohansen/Sinon.JS/issues) to fix, or pitch new features. To avoid wasting your time, please ask for feedback on feature suggestions either with [an issue](http://github.com/cjohansen/Sinon.JS/issues/new) or on [the mailing list](http://groups.google.com/group/sinonjs). ### Making a pull request Please try to [write great commit messages](http://chris.beams.io/posts/git-commit/). There are numerous benefits to great commit messages * They allow Sinon.JS users to easily understand the consequences of updating to a newer version * They help contributors understand what is going on with the codebase, allowing features and fixes to be developed faster * They save maintainers time when compiling the changelog for a new release If you're already a few commits in by the time you read this, you can still [change your commit messages](https://help.github.com/articles/changing-a-commit-message/). Also, before making your pull request, consider if your commits make sense on their own (and potentially should be multiple pull requests) or if they can be squashed down to one commit (with a great message). There are no hard and fast rules about this, but being mindful of your readers greatly help you author good commits. ### Use EditorConfig To save everyone some time, please use [EditorConfig](http://editorconfig.org), so your editor helps make sure we all use the same encoding, indentation, line endings, etc. ### Installation The Sinon.JS developer environment requires Node/NPM. Please make sure you have Node installed, and install Sinon's dependencies: $ npm install This will also install a pre-commit hook, that runs style validation on staged files. #### PhantomJS In order to run the tests, you'll need a [PhantomJS](http://phantomjs.org) global. The test suite runs well with both `1.9.x` and `2.0.0` ### Style Sinon.JS uses [ESLint](http://eslint.org) to keep consistent style. You probably want to install a plugin for your editor. The ESLint test will be run before unit tests in the CI environment, your build will fail if it doesn't pass the style check. ``` $ npm run lint ``` To ensure consistent reporting of lint warnings, you should use the same version as CI environment (defined in `package.json`) ### Run the tests This runs linting as well as unit tests in both PhantomJS and node $ npm test ##### Testing in development Sinon.JS uses [Buster.JS](http://busterjs.org), please read those docs if you're unfamiliar with it. If you just want to run tests a few times $ npm run ci-test If you're doing more than a one line edit, you'll want to have finer control and less restarting of the Buster server and PhantomJS process # start a server $ $(npm bin)/buster-server # capture a browser by pointing it to http://localhost:1111/capture # run tests (in both browser and node) $ $(npm bin)/buster-test # run tests only in browser $ $(npm bin)/buster-test --config-group browser # run tests only in node $ $(npm bin)/buster-test --config-group node If you install `Buster.JS` as a global, you can remove `$(npm-bin)/` from the lines above. ##### Testing a built version To test against a built distribution, first make sure you have a build (requires [Ruby][ruby] and [Juicer][juicer]): $ ./build [ruby]: https://www.ruby-lang.org/en/ [juicer]: http://rubygems.org/gems/juicer If the build script is unable to find Juicer, try $ ruby -rubygems build Once built, you can run the tests against the packaged version as part of the `ci-test.sh` script. ./scripts/ci-test.sh sinon-4eaad42f0715face6b53899fad7bcbc49d079417/Changelog.txt000066400000000000000000000611771276775511300225550ustar00rootroot00000000000000 v1.17.6 / 2016-09-19 ================== * Throw when sandbox.restore is given arguments (Fixes #1149) (#1151) * Fix a regression introduced in #692 (#1098) v1.17.5 / 2016-07-26 ================== * Add prepublish steps to avoid including extra files * use xhr.progress (length of body/response) for progress event * capture response length from setResponseBody * updated current tests to account for api changes * added xhr.error() method to simulate network errors * stopped treating non-200 responses as errors * Port XHR and deepEqual test cases from master * Fix deepEqual reliance on prototype hasOwnProperty() in v0.17 v1.17.4 / 2016-05-02 ==================== * Release version 1.17.4 * Improve Blob support detection logics (#1039) * Re-did #861 for v1.17 branch * Caught exceptions from async tests are thrown by simon.test. * Add tests for #947 1.17.4 / 2016-05-02 ================== * Improve Blob support detection logics (#1039) * Re-did #861 for v1.17 branch * Caught exceptions from async tests are thrown by simon.test. * Add tests for #947 1.17.3 / 2016-01-27 ================== * Fix toString() calls * Ensure sinon can run in a WebWorker * Changed the priority of which global is chosen first. * Fixed #785 by checking the global variables are set 1.17.2 / 2015-10-21 ================== * Fix #867: Walk properties only once 1.17.1 / 2015-09-26 ================== * Fix #851: Do not attempt to re-stub constructors * Fix #847: Ensure walk invokes accessors directly on target * Run tests in node 4.1.x also 1.17.0 / 2015-09-22 ================== * Fix #821 where Sinon.JS would leak a setImmdiate into global scope * Removed sinon-timers from the build. refs #811 * Added flag that, when set to true, makes sinon.logError throw errors synchronously. * Fix #777: Support non-enumerable props when stubbing objects * Made the sinon.test() function pass on errors to the callback * Expand conversion from ArrayBuffer to binary string * Add support for ArrayBuffer, blob responseTypes 1.16.1 / 2015-08-20 =================== * Bump Lolex to stop throwing an error when faking Date but not setTimeout 1.16.0 / 2015-08-19 =================== * Capture the stack on each spy call * fakeServer.create accepts configuration settings * Update Lolex to 1.3.0 * Fire onreadystatechange with event argument * Returns supersedes previous throws * Bunch of bug fixes 1.15.0 / 2015-05-30 ================== * Fixed bug where assertions don't handle functions that have a property named proxy * update license attribute * Add test coverage report * responseHeaders on abort are empty object * Fix pre-existing style error * Update documentation to cover testing built version * Update CONTRIBUTING.md with section about "Making a pull request" * Improve RELEASE.md to reduce effort when cutting a new release * Deprecate mock * Release.md * Make `npm docs sinon` work. * Run unit tests against packaged version in CI environment * Remove unused Gruntfile * Use Vanilla Buster.JS * Use `files` in package.json * Fix code style * Don't stub getter properties * Event listeners for `progress`, `load` and `readystatechange` in the `readyStateChange` function in `FakeXMLHttpRequest` are dispatched in a different order in comparison to a browser. Reorder the events dispatched to reflect general browser behaviour. * Update linting instructions in CONTRIBUTING.md * Lint all files with new linter * Update JSCS to 1.11.3 and make npm lint task verify all files * Cleanup .restore() == 1.14.1 / 2015-03-16 * Fallback for .restore() native code functions on Chrome & PhantomJS (なつき) * Restore support for sinon in IE<9 (Harry Wolff) == 1.14.0 / 2015-03-13 * Stub & spy getters & setters (Simon Zack) * Fix #702 async sinon.test using mocha interface (Mohayonao) * Add respondImmediately to fake servers (Jonathan Freeman) == 1.13.0 / 2015-03-04 * fix @depends-require mismatches (fixes AMD issues) (Ben Hockey) * Fix spy.calledWith(undefined) to return false if it was called without args * yieldsRight (Alexander Schmidt) * stubs retain function arity (Charlie Rudolph) * (AMD) use explicit define in built version * spy().reset() returns this (Ali Shakiba) * Add lengthComputable and download progress (Tamas Szebeni) * Don't setContent-type when sending FormData (AJ Ortega) * sinon.assert with spyCall (Alex Urbano) * fakeXHR requests in Node. (Jmeas) * Enhancement: run builds on docker (till@php.net) * Use FakeXDomainRequest when XHR does not support CORS. Fixes #584 (Eric Wendelin) * More lenient check for ActiveXObject * aligned sandbox.useFakeXMLHttpRequest API to documentation (Phred) * Fix #643. Returns supersedes previous throws (Adam Hull) * Safely overwrite properties in IE - no more IE files! * Add check for setInterval/clearInterval (kdpecker) * Add safety check for document.createElement (kdpecker) * Fix #633. Use a try/catch when deleting a property in IE8. (Garrick Cheung) == 1.12.1 / 2014-11-16 * Fixed lolex issue on node == 1.12.0 / 2014-11-16 * Fake timers are now extracted as lolex: http://github.com/sinonjs/lolex * Improved setImmediate fake * Proper AMD solution == 1.11.1 / 2014-10-27 * Expose match on returned sandbox (Duncan Beevers) * Fix issue #586 (Antonio D'Ettole) * Declare log_error dependency (Kurt Ruppel) == 1.11.0 / 2014-10-26 * Proper AMD support * Don't call sinon.expectation.pass if there aren't any expectations (Jeffrey Falgout) * Throw error when reset-ing while calling fake * Added xhr.response property (Gyandeep Singh) * Fixed premature sandbox destruction (Andrew Gurinovich) * Add sandbox reset method (vitalets) * A bunch of bug fixes (git log) * Various source organizational improvements (Morgan Roderick and others) == 1.10.3 / 2014-07-11 * Fix loading in Web Workers (Victor Costan) * Allow null as argument to clearTimeout and clearInterval (Lars Thorup) == 1.10.2 / 2014-06-02 * Fix `returnValue` and `exception` regression on spy calls (Maximilian Antoni) == 1.10.1 / 2014-05-30 * Improved mocha compatibility for async tests (Ming Liu) * Make the fakeServer log function overloadable (Brian M Hunt) == 1.10.0 / 2014-05-19 * Ensure that spy createCallProperties is set before function invocation (James Barwell) * XDomainRequest support (Søren Enemærke, Jonathan Sokolowski) * Correct AMD behavior (Tim Branyen) * Allow explicit naming of spies and stubs (Glen Mailer) * deepEqual test for unequal objects in calledWithExactly (Bryan Donovan) * Fix clearTimeout() for Node.js (Xiao Ma) * fix fakeServer.respond() in IE8 (John Bernardo) * Fix #448 (AMD require.amd) * Fix wrapMethod error handling (Nikita Litvin) == 1.9.1 / 2014-04-03 * Fix an issue passing `NaN` to `calledWith` (Blake Israel) * Explicate dependency on util package (Kris Kowal) * Fake timers return an object with `ref` and `unref` properties on Node (Ben Fleis) == 1.9.0 / 2014-03-05 * Add sinon.assert.match (Robin Pedersen) * Added ProgressEvent and CustomEvent. Fixes bug with progress events on IE. (Geries Handal) * prevent setRequestHeaders from being called twice (Phred) * Fix onload call, 'this' should be equal to XHR object (Niklas Andreasson) * Remove sandbox injected values on restore (Marcus Hüsgen) * Coerce matcher.or/and arguments into matchers (Glen Mailer) * Don't use buster.format any more * Fix comparison for regexp deepEqual (Matt Kern) == 1.8.2 / 2014-02-11 * Fixes an edge case with calledWithNew and spied native functions, and other functions that lack a .prototype * Add feature detection for the new ProgressEvent support == 1.8.1 / 2014-02-02 * Screwed up NPM release of 1.8.0, unable to replace it == 1.8.0 / 2014-02-02 * Add clearImmediate mocking support to the timers API (Tim Perry) * Mirror custom Date properties when faking time * Improved Weinre support * Update call properties even if exceptions are thrown (Tim Perry) * Update call properties even if exceptions are thrown (Tim Perry) * Reverse matching order for fake server (Gordon L. Hempton) * Fix restoring globals on another frame fails on Firefox (Burak Yiğit Kaya) * Handle stubbing falsey properties (Tim Perry) * Set returnValues correctly when the spied function is called as a constructor (Tim Perry) * When creating a sandbox, do not overwrite existing properties when inject properties into an object (Sergio Cinos) * Added withCredentials property to fake xhr (Geries) * Refine behavior withArgs error message (Tim Fischbach) * Auto-respond to successive requests made with a single XHR object (Jan Suchý) * Add the ability for mock to accept sinon.match matchers as expected arguments (Zcicala) * Adding support for XMLHttpRequest.upload to FakeXMLHttpRequest (Benjamin Coe) * Allow onCall to be combined with returns* and throwsException in stub behavior sequences (Tim Fischbach) * Fixed deepEqual to detect properties on array objects * Fixed problem with chained timers with delay=0 (Ian Lewis) * Use formatio in place of buster-format (Devin Weaver) == 1.7.3 / 2013-06-20 * Removed use of array forEach, breaks in older browsers (Martin Hansen) * sinon.deepEqual(new Date(0), new Date()) returns true (G.Serebryanskyi) == 1.7.2 / 2013-05-08 * Sinon 1.7 has split calls out to a separate file. This caused some problems, so 1.7.2 ships with spyCall as part of spy.js like it used to be. == 1.7.1 / 2013-05-07 * Fake XMLHttpRequest updated to call onerror and onsuccess callbacks, fixing jQuery 2.0 problems (Roman Potashow) * Implement XMLHttpRequest progress event api (Marten Lienen) * Added sinon.restore() (Jonny Reeves) * Fix bug where throwing a string was handled incorrectly by Sinon (Brandon Heyer) * Web workers support (Victor Costan) == 1.7.0 * Failed release, see 1.7.1 == 1.6.0 / 2013-02-18 * Add methods to spyCall interface: callArgOn, callArgOnWith, yieldOn, yieldToOn (William Sears) * sinon.createStubInstance creates a fully stubbed instance from a constructor (Shawn Krisman) * resetBehavior resets fakes created by withArgs (Martin Sander) * The fake server now logs to sinon.log, if set (Luis Cardoso) * Cleaner npm package that also includes pkg/sinon.js and pkg/sinon-ie.js for cases where npm is used to install Sinon for browser usage (Domenic Denicola) * Improved spy formatter %C output (Farid Neshat) * clock.tick returns clock.now (Michael Jackson) * Fixed issue #248 with callOrder assertion Did not fail if the last given spy was never called (Maximilian Antoni) * Fixed issue with setResponseHeader for synchronous requests (goligo) * Remove msSetImmediate; it only existed in IE10 previews (Domenic Denicola) * Fix #231: not always picking up the latest calls to callsArgWith, etc. (Domenic Denicola) * Fix failing anonymous mock expectations == 1.5.2 / 2012-11-28 * Revert stub.reset changes that caused existing tests to fail. == 1.5.1 / 2012-11-27 * Ensure window.Image can be stubbed. (Adrian Phinney) * Fix spy() in IE 8 (Scott Andrews) * Fix sinon base in IE 8 (Scott Andrews) * Format arguments ouput when mock excpetation is not met (kbackowski) * Calling spy.reset directly from stub.reset (Thomas Meyer) == 1.5.0 / 2012-10-19 * Don't force "use strict" on Sinon consumers * Don't assume objects have hasOwnProperties. Fixes problem with e.g. stubbing properties on process.env * Preserve function length for spy (Maximilian Antoni) * Add 'invokeCallback' alias for 'yield' on calls (Maximilian Antoni) * Added matcher support for calledOn (Maximilian Antoni) * Retain original expectation messages, for failed mocks under sinon.test (Giorgos Giannoutsos) * Allow yields* and callsArg* to create sequences of calls. (Domenic Denicola) * sinon.js can catch itself in endless loop while filling stub prototype with asynch methods (Jan Kopriva) == 1.4.2 / 2012-07-11 * sinon.match for arrays (Maximilian Antoni) == 1.4.1 / 2012-07-11 * Strengthen a Node.JS inference to avoid quirky behavior with Mocha (which provides a shim process object) == 1.4.0 / 2012-07-09 * Argument matchers (Maximillian Antoni) sinon.match.{any, same, typeOf, instanceOf, has, hasOwn, defined, truthy, falsy} as well as typeOf shortcuts for boolean, number, string, object, function, array, regexp and date. The result of a call can be used with spy.calledWith. * spy.returned now works with matchers and compares objects deeply. * Matcher assertions: calledWithMatch, alwaysCalledWithMatch and neverCalledWithMatch * calledWithNew and alwaysCalledWithNew for assert (Maximilian Antoni) * Easier stubbed fluent interfaces: stub.returnsThis() (Glen Mailer) * allow yields() and family to be used along with returns()/throws() and family (Glen Mailer) * Async versions `callsArg*` and `yields*` for stubs (TEHEK) * Format args when doing `spy.printf("%*")` (Domenic Denicola) * Add notCalled property to spies * Fix: spy.reset did not reset fakes created by spy.withArgs (Maximilian Antoni) * Properly restore stubs when stubbing entire objects through the sandbox (Konrad Holowinski) * Restore global methods properly - delete properties that where not own properties (Keith Cirkel) * setTimeout and setInterval pass arguments (Rodion Vynnychenko) * Timer callbacks that contain a clock.tick no longer fails (Wesley Waser) * spy(undefined, "property") now throws * Prevent multiple restore for fake timers (Kevin Decker) * Fix toString format under Node (Kevin Decker) * Mock expectations emit success and failure events (Kevin Decker) * Development improvement: Use Buster.JS to test Sinon * Fix bug where expect.atLeast failed when minimum calls where received * Make fake server safe to load on node.js * Add support for no args on .withArgs and .withExactArgs (Tek Nynja) * Avoid hasOwnProperty for host objects == 1.3.2 / 2012-03-11 * Stronger Node inference in sandbox * Fixed issue with sinon.useFakeTimers() and Rhino.js 1.7R3 * Formatting brush-up * FIX Internet Explorer misreporting the type of Function objects originating in an external window as "object" instead of "function". * New methods stub.callsArgOn, stub.callsArgOnWith, stub.yieldsOn, stub.yieldsToOn * Implemented * Fixing `clearTimeout` to not throw when called for nonexistant IDs. * Spys that are created using 'withArgs' now get initialized with previous calls to the original spy. * Minor bug fixes and docs cleanup. == 1.3.1 / 2012-01-04 * Fix bug in core sinon: isNode was used for both a variable and a function, causing load errors and lots of bugs. Should have never left the door. == 1.3.0 / 2012-01-01 * Support using bare functions as fake server response handlers (< 1.3.0 required URL and/or method matcher too) * Log some internal errors to sinon.log (defaults to noop). Set sinon.log to your logging utility of choice for better feedback when. * White-list fake XHRs: Allows some fake requests and some that fall through to the backend server (Tim Ruffles) * Decide Date.now support at fake-time. Makes it possible to load something that polyfills Date.now after Sinon loaded and still have Date.now on fake Dates. * Mirror properties on replaced function properties * New methods: spy.yield(), spy.yieldTo(), spy.callArg() and spy.callArgWith() can be used to invoke callbacks passed to spies (while avoiding the mock-like upfront yields() and friends). invokeCallback is available as an alias for yield for people working with strict mode. (Maximilian Antoni) * New properties: spy.firstCall, spy.secondCall, spy.thirdCall and spy.lastCall. (Maximilian Antoni) * New method: stub.returnsArg(), causes stub to return one of its arguments. (Gavin Huang) * Stubs now work for inherited methods. This was previously prohibited to avoid stubbing not-yet-implemented methods. (Felix Geisendörfer) * server.respond() can now accept the same arguments as server.respondWith() for quick-and-dirty respondWith+respond. (Gavin Huang) * Format objects with buster-format in the default bundle. Default to util.inspect on node unless buster-format is available (not a hard dependency, more like a 'preference'). * Bug fix: Make sure XHRs can complete even if onreadystatechange handler fails * Bug fix: Mirror entire Date.prototype, including toUTCString when faking * Bug fix: Default this object to global in exposed asserts * Bug fix: sinon.test: use try/finally instead of catch and throw - preserves stack traces (Kevin Turner) * Bug fix: Fake `setTimeout` now returns ids greater than 0. (Domenic Denicola) * Bug fix: NPM install warning (Felix Geisendörfer) * Bug fix: Fake timers no longer swallows exceptions (Felix Geisendörfer) * Bug fix: Properly expose all needed asserts for node * Bug fix: wrapMethod on window property (i.e. when stubbing/spying on global functions) * Bug fix: Quote "yield" (Ben Hockey) * Bug fix: callOrder works correctly when spies have been called multiple times == 1.2.0 / 2011-09-27 * Bug fix: abort() switches state to DONE when OPENED and sent. Fix by Tristan Koch. * Bug fix: Mootools uses MSXML2.XMLHTTP as objectId, which Sinon matched with different casing. Fix by Olmo Maldonado. * Bug fix: When wrapping a non-owned property, restore now removes the wrapper instead of replacing it. Fix by Will Butler. * Bug fix: Make it possibly to stub Array.prototype.push by not using that method directly inside Sinon. * Bug fix: Don't assume that req.requestBody is a string in the fake server. * Added spy.printf(format) to print a nicely formatted message with details about a spy. * Garbage collection: removing fakes from collections when restoring the original methods. Fix by Tristan Koch. * Add spy.calledWithNew to check if a function was used as a constructor * Add spy.notCalledWith(), spy.neverCalledWith() and sinon.assert.neverCalledWith. By Max Antoni * Publicly expose sinon.expectation.fail to allow tools to integrate with mock expectations. * Fake XMLHttpRequests now support a minimal portion of the events API, making them work seamlessly with e.g. SproutCode (which uses xhr.addEventListener("readystatechange"). Partially by Sven Fuchs. == 1.1.1 / 2011-05-17 * Fix broken mock verification in CommonJS when not including the full Sinon package. == 1.1.0 / 2011-05-04 * The fake server now has a autoRespond method which allows it to respond to requests on the fly (asynchronously), making it a good fit for mockup development * Stubs and spies now has a withArgs method. Using it allows you to create several spies/stubs for the same method, filtered by received arguments * Stubs now has yields and yieldsTo methods for fuzzily invoking callbacks. They work like callsArgAt only by inferring what callback to invoke, and yieldsTo can invoke callbacks in object "options" arguments. * Allow sandboxes/collections to stub any property so long as the object has the property as an own property * Significantly improve error reporting from failed mock expecations. Now prints all met and unmet expectations with expected and received arguments * Allow mock expectations to be consumed in any order * Add pretty printing of all calls when assertions fail * Fix bug: Stub exception message ended up as "undefined" (string) if not specified * Pass capture groups in URLs to fakeServer function handlers * Pass through return value from test function in testCase * typeof require is not enough to assume node, also use typeof module * Don't use Object.create in sinon.create. In the off chance that someone stubs it, sinon will fail mysteriously (Thanks to Espen Dalløkken) * Catch exceptions when parsing DOM elements "on a hunch" When responding to XHRs, Sinon acts like most browsers and try to parse the response into responseXML if Content-Type indicates XML or HTML. However, it also does this if the type is not set. Obviously, this may misfire and should be caught. * Fix fakeServer.respond() to not drop requests when they are queued during the processing of an existing queue. (Sven Fuchs) * Clean up module loading in CommonJS environments (Node.js still the only tested such environment). No longer (temporarily) modifies require.paths, always loads all modules. == 1.0.2 / 2011-02-22 * Fix JSON bug in package.json * Sandbox no longer tries to use a fake server if config says so, but server is not loaded == 1.0.1 / 2010-12-20 * Make sure sinon.sandbox is exposed in node.js (fix by Gord Tanner) == 1.0.0 / 2010-12-08 * Switched indentation from 2 to 4 spaces :) * Node.js compatibility improvements * Remove magic booleans from sinon.assert.expose, replace with option object * Put QUnit adapter in it's own repository * Update build script to build standalone timers and server files * Breaking change: thisObj -> thisValue Change brings consistency to the code-base, always use thisValue * Add sinon.assert.pass callback for successful assertions * Extract sandbox configuration from sinon.test Refactored sinon.test to not do all the heavy lifting in creating sandbox objects from sinon.config. Now sinon.sandbox.create accepts an optional configuration that can be retrieved through sinon.getConfig({ ... }) - or, to match previous behavior, through sinon.getConfig(sinon.config); The default configuration now lives in sinon.defaultConfig rather than the previous sinon.test. This change enables external tools, such as test framework adapters, to easily create configurable sandboxes without going through sinon.test * Rewrite sinon.clock.tick to fix bug and make implementation clearer * Test config load correct files * Make timers and XHR truly standalone by splitting the IE work-around in two files * Don't fail when comparing DOM elements in sinon.deepEqual (used in calledWith(...)) * Should mirror properties on Date when faking it * Added and updated configuration for both JsLint and JavaScript lint * [August Lilleaas] The build script can optionally build a file without the version name in it, by passing 'plain', i.e. './build plain'. Useful when using the build script to build and use sinon programatically, so one can 'cp path/to/sinon/pkg/sinon.js my/scripts/' * [August Lilleaas] Checking and warning if we got a load error and rubygems isn't present. * [August Lilleaas] Updating build script to be runnable from any directory. Current working directory doesn't have to be repo root. == 0.8.0 / 2010-10-30 * sinon.wrapMethod no longer accepts faking already faked methods * sinon-qunit 'plugin' * sinon.test / sinon.config can now expose the sandbox object == 0.7.2 / 2010-10-25 * Add sinon.sandbox.create back in * Fix bug where clock.tick would fire timeouts in intervals when setInterval was also called == 0.7.1 / 2010-10-16 * The fake server will now match paths against full URLs, meaning that server.respondWith("/", "OK"); will match requests for "http://currentHost/". * Improved toString method for spies and stubs which leads to more precise error messages from sinon.assert.* == 0.7.0 / 2010-09-19 * sinon.useFakeTimers now fakes the Date constructor by default * sinon.testCase now fakes XHR and timers by default * sinon.config controls the behavior of sinon.testCase * Fixed bug in clock.tick - now fires timers in correct order * Added the ability to tick a clock string for longer ticks. Passing a number causes the clock to tick the specified amount of milliseconds, passing a string like "12:32" ticks 12 minutes and 32 seconds. * calledBefore and calledAfter for individual calls * New assertions sinon.assert.notCalled sinon.assert.calledOnce sinon.assert.calledTwice sinon.assert.calledThrice * sinon.test now throws if passed anything other than a function * sinon.testCase now throws if passed anything other than an object * sinon.{spy,stub}(obj, method) now throws if the property is not an existing function - helps avoid perpetuating typo bugs * Vastly improved error messages from assertions * Spies/stubs/expectations can have their names resolved in many cases * Removed feature where sinon.testCase allowed for nested test cases (does not belong in Sinon.JS) * Organizational change: src/ becomes lib/ Helps npm compatibility * Thanks to Cory Flanigan for help on npm compatibility == 0.6.2 / 2010-08-12 * Fixed another bug in sinon.fakeServerWithClock where consecutive respond() calls did not trigger timeouts. == 0.6.1 / 2010-08-12 * Fixed a bug in sinon.fakeServerWithClock where the clock was ticked before the server had responded to all requests, resulting in objects not having been responded to by the time the timeout ran. == 0.6.0 / 2010-08-10 * FakeXMLHttpRequest * sinon.useFakeXMLHttpRequest * sinon.fakeServer * sinon.fakeServerWithClock * Improved fake timers implementation, made them work properly in IE 6-8 * Improved sinon.sandbox * Added useFakeServer * Added inject method * Improved sinon.test method * Made configuration aware * Now uses sinon.sandbox in place of sinon.collection * Changed default configuration for sinon.test, breaking compatibility with 0.5.0 - can be changed through sinon.config == 0.5.0 / 2010-06-09 * Initial release * Spies, stubs, mocks * Assertions * collections, test, testCase * Fake timers (half-baked) sinon-4eaad42f0715face6b53899fad7bcbc49d079417/LICENSE000066400000000000000000000030441276775511300211170ustar00rootroot00000000000000(The BSD License) Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Christian Johansen nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. sinon-4eaad42f0715face6b53899fad7bcbc49d079417/README.md000066400000000000000000000035161276775511300213750ustar00rootroot00000000000000# Sinon.JS [![Build status](https://secure.travis-ci.org/cjohansen/Sinon.JS.svg?branch=master)](http://travis-ci.org/cjohansen/Sinon.JS) Standalone and test framework agnostic JavaScript test spies, stubs and mocks. ## Installation via [npm (node package manager)](http://github.com/isaacs/npm) $ npm install sinon via [NuGet (package manager for Microsoft development platform)](https://www.nuget.org/packages/SinonJS) Install-Package SinonJS or install via git by cloning the repository and including sinon.js in your project, as you would any other third party library. Don't forget to include the parts of Sinon.JS that you want to use as well (i.e. spy.js). ## Usage See the [sinon project homepage](http://sinonjs.org/) for documentation on usage. If you have questions that are not covered by the documentation, please post them to the [Sinon.JS mailing list](http://groups.google.com/group/sinonjs) or drop by #sinon.js on irc.freenode.net:6667 ### Important: AMD needs pre-built version Sinon.JS *as source* **doesn't work with AMD loaders** (when they're asynchronous, like loading via script tags in the browser). For that you will have to use a pre-built version. You can either [build it yourself](CONTRIBUTING.md#testing-a-built-version) or get a numbered version from http://sinonjs.org. This might or might not change in future versions, depending of outcome of investigations. Please don't report this as a bug, just use pre-built versions. ## Goals * No global pollution * Easy to use * Require minimal “integration” * Easy to embed seamlessly with any testing framework * Easily fake any interface * Ship with ready-to-use fakes for XMLHttpRequest, timers and more ## Contribute? See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how you can contribute to Sinon.JS sinon-4eaad42f0715face6b53899fad7bcbc49d079417/RELEASE.md000066400000000000000000000013501276775511300215120ustar00rootroot00000000000000# Rolling Sinon releases You'll need a working installation of [git-extras](https://github.com/tj/git-extras) for this. ## Update Changelog.txt Compile interesting highlights from [`git changelog`](https://github.com/tj/git-extras/blob/master/Commands.md#git-changelog) into Changelog.md git changelog --no-merges ## Update AUTHORS git authors --list > AUTHORS ## Create a new version Update package.json and create a new tag. ``` $ npm version x.y.z ``` ## Publish to NPM ``` $ npm publish ``` ## Update static site ### Copy files into the static site cp Changelog.txt ../sinon-docs/resources/public/. cp pkg/* ../sinon-docs/resources/public/releases/. ### Publish the site cd ../sinon-docs && ./publish.sh sinon-4eaad42f0715face6b53899fad7bcbc49d079417/build000077500000000000000000000073771276775511300211540ustar00rootroot00000000000000#!/usr/bin/env ruby begin require "juicer/merger/javascript_merger" rescue LoadError => err puts "Install juicer ruby gem to build Sinon.JS. Try `gem install juicer`." if !defined?(Gem) puts "RubyGems is not loaded. Perhaps that is why juicer can not be found?" end exit end require "fileutils" require "pathname" def add_license(file, version) contents = File.read(file) File.open(file, "w") do |f| f.puts <= 0) { return args[callArgAt]; } var argumentList; if (callArgAt === useLeftMostCallback) { argumentList = args; } if (callArgAt === useRightMostCallback) { argumentList = slice.call(args).reverse(); } var callArgProp = behavior.callArgProp; for (var i = 0, l = argumentList.length; i < l; ++i) { if (!callArgProp && typeof argumentList[i] === "function") { return argumentList[i]; } if (callArgProp && argumentList[i] && typeof argumentList[i][callArgProp] === "function") { return argumentList[i][callArgProp]; } } return null; } function makeApi(sinon) { function getCallbackError(behavior, func, args) { if (behavior.callArgAt < 0) { var msg; if (behavior.callArgProp) { msg = sinon.functionName(behavior.stub) + " expected to yield to '" + behavior.callArgProp + "', but no object with such a property was passed."; } else { msg = sinon.functionName(behavior.stub) + " expected to yield, but no callback was passed."; } if (args.length > 0) { msg += " Received [" + join.call(args, ", ") + "]"; } return msg; } return "argument at index " + behavior.callArgAt + " is not a function: " + func; } function callCallback(behavior, args) { if (typeof behavior.callArgAt === "number") { var func = getCallback(behavior, args); if (typeof func !== "function") { throw new TypeError(getCallbackError(behavior, func, args)); } if (behavior.callbackAsync) { nextTick(function () { func.apply(behavior.callbackContext, behavior.callbackArguments); }); } else { func.apply(behavior.callbackContext, behavior.callbackArguments); } } } var proto = { create: function create(stub) { var behavior = sinon.extend({}, sinon.behavior); delete behavior.create; behavior.stub = stub; return behavior; }, isPresent: function isPresent() { return (typeof this.callArgAt === "number" || this.exception || typeof this.returnArgAt === "number" || this.returnThis || this.returnValueDefined); }, invoke: function invoke(context, args) { callCallback(this, args); if (this.exception) { throw this.exception; } else if (typeof this.returnArgAt === "number") { return args[this.returnArgAt]; } else if (this.returnThis) { return context; } return this.returnValue; }, onCall: function onCall(index) { return this.stub.onCall(index); }, onFirstCall: function onFirstCall() { return this.stub.onFirstCall(); }, onSecondCall: function onSecondCall() { return this.stub.onSecondCall(); }, onThirdCall: function onThirdCall() { return this.stub.onThirdCall(); }, withArgs: function withArgs(/* arguments */) { throw new Error( "Defining a stub by invoking \"stub.onCall(...).withArgs(...)\" " + "is not supported. Use \"stub.withArgs(...).onCall(...)\" " + "to define sequential behavior for calls with certain arguments." ); }, callsArg: function callsArg(pos) { if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } this.callArgAt = pos; this.callbackArguments = []; this.callbackContext = undefined; this.callArgProp = undefined; this.callbackAsync = false; return this; }, callsArgOn: function callsArgOn(pos, context) { if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = pos; this.callbackArguments = []; this.callbackContext = context; this.callArgProp = undefined; this.callbackAsync = false; return this; }, callsArgWith: function callsArgWith(pos) { if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } this.callArgAt = pos; this.callbackArguments = slice.call(arguments, 1); this.callbackContext = undefined; this.callArgProp = undefined; this.callbackAsync = false; return this; }, callsArgOnWith: function callsArgWith(pos, context) { if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = pos; this.callbackArguments = slice.call(arguments, 2); this.callbackContext = context; this.callArgProp = undefined; this.callbackAsync = false; return this; }, yields: function () { this.callArgAt = useLeftMostCallback; this.callbackArguments = slice.call(arguments, 0); this.callbackContext = undefined; this.callArgProp = undefined; this.callbackAsync = false; return this; }, yieldsRight: function () { this.callArgAt = useRightMostCallback; this.callbackArguments = slice.call(arguments, 0); this.callbackContext = undefined; this.callArgProp = undefined; this.callbackAsync = false; return this; }, yieldsOn: function (context) { if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = useLeftMostCallback; this.callbackArguments = slice.call(arguments, 1); this.callbackContext = context; this.callArgProp = undefined; this.callbackAsync = false; return this; }, yieldsTo: function (prop) { this.callArgAt = useLeftMostCallback; this.callbackArguments = slice.call(arguments, 1); this.callbackContext = undefined; this.callArgProp = prop; this.callbackAsync = false; return this; }, yieldsToOn: function (prop, context) { if (typeof context !== "object") { throw new TypeError("argument context is not an object"); } this.callArgAt = useLeftMostCallback; this.callbackArguments = slice.call(arguments, 2); this.callbackContext = context; this.callArgProp = prop; this.callbackAsync = false; return this; }, throws: throwsException, throwsException: throwsException, returns: function returns(value) { this.returnValue = value; this.returnValueDefined = true; this.exception = undefined; return this; }, returnsArg: function returnsArg(pos) { if (typeof pos !== "number") { throw new TypeError("argument index is not number"); } this.returnArgAt = pos; return this; }, returnsThis: function returnsThis() { this.returnThis = true; return this; } }; function createAsyncVersion(syncFnName) { return function () { var result = this[syncFnName].apply(this, arguments); this.callbackAsync = true; return result; }; } // create asynchronous versions of callsArg* and yields* methods for (var method in proto) { // need to avoid creating anotherasync versions of the newly added async methods if (proto.hasOwnProperty(method) && method.match(/^(callsArg|yields)/) && !method.match(/Async/)) { proto[method + "Async"] = createAsyncVersion(method); } } sinon.behavior = proto; return proto; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./extend"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/call.js000066400000000000000000000172311276775511300232620ustar00rootroot00000000000000/** * @depend util/core.js * @depend match.js * @depend format.js */ /** * Spy calls * * @author Christian Johansen (christian@cjohansen.no) * @author Maximilian Antoni (mail@maxantoni.de) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen * Copyright (c) 2013 Maximilian Antoni */ (function (sinonGlobal) { "use strict"; var slice = Array.prototype.slice; function makeApi(sinon) { function throwYieldError(proxy, text, args) { var msg = sinon.functionName(proxy) + text; if (args.length) { msg += " Received [" + slice.call(args).join(", ") + "]"; } throw new Error(msg); } var callProto = { calledOn: function calledOn(thisValue) { if (sinon.match && sinon.match.isMatcher(thisValue)) { return thisValue.test(this.thisValue); } return this.thisValue === thisValue; }, calledWith: function calledWith() { var l = arguments.length; if (l > this.args.length) { return false; } for (var i = 0; i < l; i += 1) { if (!sinon.deepEqual(arguments[i], this.args[i])) { return false; } } return true; }, calledWithMatch: function calledWithMatch() { var l = arguments.length; if (l > this.args.length) { return false; } for (var i = 0; i < l; i += 1) { var actual = this.args[i]; var expectation = arguments[i]; if (!sinon.match || !sinon.match(expectation).test(actual)) { return false; } } return true; }, calledWithExactly: function calledWithExactly() { return arguments.length === this.args.length && this.calledWith.apply(this, arguments); }, notCalledWith: function notCalledWith() { return !this.calledWith.apply(this, arguments); }, notCalledWithMatch: function notCalledWithMatch() { return !this.calledWithMatch.apply(this, arguments); }, returned: function returned(value) { return sinon.deepEqual(value, this.returnValue); }, threw: function threw(error) { if (typeof error === "undefined" || !this.exception) { return !!this.exception; } return this.exception === error || this.exception.name === error; }, calledWithNew: function calledWithNew() { return this.proxy.prototype && this.thisValue instanceof this.proxy; }, calledBefore: function (other) { return this.callId < other.callId; }, calledAfter: function (other) { return this.callId > other.callId; }, callArg: function (pos) { this.args[pos](); }, callArgOn: function (pos, thisValue) { this.args[pos].apply(thisValue); }, callArgWith: function (pos) { this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1))); }, callArgOnWith: function (pos, thisValue) { var args = slice.call(arguments, 2); this.args[pos].apply(thisValue, args); }, "yield": function () { this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0))); }, yieldOn: function (thisValue) { var args = this.args; for (var i = 0, l = args.length; i < l; ++i) { if (typeof args[i] === "function") { args[i].apply(thisValue, slice.call(arguments, 1)); return; } } throwYieldError(this.proxy, " cannot yield since no callback was passed.", args); }, yieldTo: function (prop) { this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1))); }, yieldToOn: function (prop, thisValue) { var args = this.args; for (var i = 0, l = args.length; i < l; ++i) { if (args[i] && typeof args[i][prop] === "function") { args[i][prop].apply(thisValue, slice.call(arguments, 2)); return; } } throwYieldError(this.proxy, " cannot yield to '" + prop + "' since no callback was passed.", args); }, getStackFrames: function () { // Omit the error message and the two top stack frames in sinon itself: return this.stack && this.stack.split("\n").slice(3); }, toString: function () { var callStr = this.proxy ? this.proxy.toString() + "(" : ""; var args = []; if (!this.args) { return ":("; } for (var i = 0, l = this.args.length; i < l; ++i) { args.push(sinon.format(this.args[i])); } callStr = callStr + args.join(", ") + ")"; if (typeof this.returnValue !== "undefined") { callStr += " => " + sinon.format(this.returnValue); } if (this.exception) { callStr += " !" + this.exception.name; if (this.exception.message) { callStr += "(" + this.exception.message + ")"; } } if (this.stack) { callStr += this.getStackFrames()[0].replace(/^\s*(?:at\s+|@)?/, " at "); } return callStr; } }; callProto.invokeCallback = callProto.yield; function createSpyCall(spy, thisValue, args, returnValue, exception, id, stack) { if (typeof id !== "number") { throw new TypeError("Call id is not a number"); } var proxyCall = sinon.create(callProto); proxyCall.proxy = spy; proxyCall.thisValue = thisValue; proxyCall.args = args; proxyCall.returnValue = returnValue; proxyCall.exception = exception; proxyCall.callId = id; proxyCall.stack = stack; return proxyCall; } createSpyCall.toString = callProto.toString; // used by mocks sinon.spyCall = createSpyCall; return createSpyCall; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./match"); require("./format"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/collection.js000066400000000000000000000110601276775511300244740ustar00rootroot00000000000000/** * @depend util/core.js * @depend spy.js * @depend stub.js * @depend mock.js */ /** * Collections of stubs, spies and mocks. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinonGlobal) { "use strict"; var push = [].push; var hasOwnProperty = Object.prototype.hasOwnProperty; function getFakes(fakeCollection) { if (!fakeCollection.fakes) { fakeCollection.fakes = []; } return fakeCollection.fakes; } function each(fakeCollection, method) { var fakes = getFakes(fakeCollection); for (var i = 0, l = fakes.length; i < l; i += 1) { if (typeof fakes[i][method] === "function") { fakes[i][method](); } } } function compact(fakeCollection) { var fakes = getFakes(fakeCollection); var i = 0; while (i < fakes.length) { fakes.splice(i, 1); } } function makeApi(sinon) { var collection = { verify: function resolve() { each(this, "verify"); }, restore: function restore() { each(this, "restore"); compact(this); }, reset: function restore() { each(this, "reset"); }, verifyAndRestore: function verifyAndRestore() { var exception; try { this.verify(); } catch (e) { exception = e; } this.restore(); if (exception) { throw exception; } }, add: function add(fake) { push.call(getFakes(this), fake); return fake; }, spy: function spy() { return this.add(sinon.spy.apply(sinon, arguments)); }, stub: function stub(object, property, value) { if (property) { var original = object[property]; if (typeof original !== "function") { if (!hasOwnProperty.call(object, property)) { throw new TypeError("Cannot stub non-existent own property " + property); } object[property] = value; return this.add({ restore: function () { object[property] = original; } }); } } if (!property && !!object && typeof object === "object") { var stubbedObj = sinon.stub.apply(sinon, arguments); for (var prop in stubbedObj) { if (typeof stubbedObj[prop] === "function") { this.add(stubbedObj[prop]); } } return stubbedObj; } return this.add(sinon.stub.apply(sinon, arguments)); }, mock: function mock() { return this.add(sinon.mock.apply(sinon, arguments)); }, inject: function inject(obj) { var col = this; obj.spy = function () { return col.spy.apply(col, arguments); }; obj.stub = function () { return col.stub.apply(col, arguments); }; obj.mock = function () { return col.mock.apply(col, arguments); }; return obj; } }; sinon.collection = collection; return collection; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./mock"); require("./spy"); require("./stub"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/extend.js000066400000000000000000000065631276775511300236440ustar00rootroot00000000000000/** * @depend util/core.js */ (function (sinonGlobal) { "use strict"; function makeApi(sinon) { // Adapted from https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug var hasDontEnumBug = (function () { var obj = { constructor: function () { return "0"; }, toString: function () { return "1"; }, valueOf: function () { return "2"; }, toLocaleString: function () { return "3"; }, prototype: function () { return "4"; }, isPrototypeOf: function () { return "5"; }, propertyIsEnumerable: function () { return "6"; }, hasOwnProperty: function () { return "7"; }, length: function () { return "8"; }, unique: function () { return "9"; } }; var result = []; for (var prop in obj) { if (obj.hasOwnProperty(prop)) { result.push(obj[prop]()); } } return result.join("") !== "0123456789"; })(); /* Public: Extend target in place with all (own) properties from sources in-order. Thus, last source will * override properties in previous sources. * * target - The Object to extend * sources - Objects to copy properties from. * * Returns the extended target */ function extend(target /*, sources */) { var sources = Array.prototype.slice.call(arguments, 1); var source, i, prop; for (i = 0; i < sources.length; i++) { source = sources[i]; for (prop in source) { if (source.hasOwnProperty(prop)) { target[prop] = source[prop]; } } // Make sure we copy (own) toString method even when in JScript with DontEnum bug // See https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug if (hasDontEnumBug && source.hasOwnProperty("toString") && source.toString !== target.toString) { target.toString = source.toString; } } return target; } sinon.extend = extend; return sinon.extend; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/format.js000066400000000000000000000047651276775511300236470ustar00rootroot00000000000000/** * @depend util/core.js */ /** * Format functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2014 Christian Johansen */ (function (sinonGlobal, formatio) { "use strict"; function makeApi(sinon) { function valueFormatter(value) { return "" + value; } function getFormatioFormatter() { var formatter = formatio.configure({ quoteStrings: false, limitChildrenCount: 250 }); function format() { return formatter.ascii.apply(formatter, arguments); } return format; } function getNodeFormatter() { try { var util = require("util"); } catch (e) { /* Node, but no util module - would be very old, but better safe than sorry */ } function format(v) { var isObjectWithNativeToString = typeof v === "object" && v.toString === Object.prototype.toString; return isObjectWithNativeToString ? util.inspect(v) : v; } return util ? format : valueFormatter; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var formatter; if (isNode) { try { formatio = require("formatio"); } catch (e) {} // eslint-disable-line no-empty } if (formatio) { formatter = getFormatioFormatter(); } else if (isNode) { formatter = getNodeFormatter(); } else { formatter = valueFormatter; } sinon.format = formatter; return sinon.format; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon, // eslint-disable-line no-undef typeof formatio === "object" && formatio // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/log_error.js000066400000000000000000000043501276775511300243370ustar00rootroot00000000000000/** * @depend util/core.js */ /** * Logs errors * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2014 Christian Johansen */ (function (sinonGlobal) { "use strict"; // cache a reference to setTimeout, so that our reference won't be stubbed out // when using fake timers and errors will still get logged // https://github.com/cjohansen/Sinon.JS/issues/381 var realSetTimeout = setTimeout; function makeApi(sinon) { function log() {} function logError(label, err) { var msg = label + " threw exception: "; function throwLoggedError() { err.message = msg + err.message; throw err; } sinon.log(msg + "[" + err.name + "] " + err.message); if (err.stack) { sinon.log(err.stack); } if (logError.useImmediateExceptions) { throwLoggedError(); } else { logError.setTimeout(throwLoggedError, 0); } } // When set to true, any errors logged will be thrown immediately; // If set to false, the errors will be thrown in separate execution frame. logError.useImmediateExceptions = false; // wrap realSetTimeout with something we can stub in tests logError.setTimeout = function (func, timeout) { realSetTimeout(func, timeout); }; var exports = {}; exports.log = sinon.log = log; exports.logError = sinon.logError = logError; return exports; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/match.js000066400000000000000000000207521276775511300234450ustar00rootroot00000000000000/** * @depend util/core.js * @depend typeOf.js */ /*jslint eqeqeq: false, onevar: false, plusplus: false*/ /*global module, require, sinon*/ /** * Match functions * * @author Maximilian Antoni (mail@maxantoni.de) * @license BSD * * Copyright (c) 2012 Maximilian Antoni */ (function (sinonGlobal) { "use strict"; function makeApi(sinon) { function assertType(value, type, name) { var actual = sinon.typeOf(value); if (actual !== type) { throw new TypeError("Expected type of " + name + " to be " + type + ", but was " + actual); } } var matcher = { toString: function () { return this.message; } }; function isMatcher(object) { return matcher.isPrototypeOf(object); } function matchObject(expectation, actual) { if (actual === null || actual === undefined) { return false; } for (var key in expectation) { if (expectation.hasOwnProperty(key)) { var exp = expectation[key]; var act = actual[key]; if (isMatcher(exp)) { if (!exp.test(act)) { return false; } } else if (sinon.typeOf(exp) === "object") { if (!matchObject(exp, act)) { return false; } } else if (!sinon.deepEqual(exp, act)) { return false; } } } return true; } function match(expectation, message) { var m = sinon.create(matcher); var type = sinon.typeOf(expectation); switch (type) { case "object": if (typeof expectation.test === "function") { m.test = function (actual) { return expectation.test(actual) === true; }; m.message = "match(" + sinon.functionName(expectation.test) + ")"; return m; } var str = []; for (var key in expectation) { if (expectation.hasOwnProperty(key)) { str.push(key + ": " + expectation[key]); } } m.test = function (actual) { return matchObject(expectation, actual); }; m.message = "match(" + str.join(", ") + ")"; break; case "number": m.test = function (actual) { // we need type coercion here return expectation == actual; // eslint-disable-line eqeqeq }; break; case "string": m.test = function (actual) { if (typeof actual !== "string") { return false; } return actual.indexOf(expectation) !== -1; }; m.message = "match(\"" + expectation + "\")"; break; case "regexp": m.test = function (actual) { if (typeof actual !== "string") { return false; } return expectation.test(actual); }; break; case "function": m.test = expectation; if (message) { m.message = message; } else { m.message = "match(" + sinon.functionName(expectation) + ")"; } break; default: m.test = function (actual) { return sinon.deepEqual(expectation, actual); }; } if (!m.message) { m.message = "match(" + expectation + ")"; } return m; } matcher.or = function (m2) { if (!arguments.length) { throw new TypeError("Matcher expected"); } else if (!isMatcher(m2)) { m2 = match(m2); } var m1 = this; var or = sinon.create(matcher); or.test = function (actual) { return m1.test(actual) || m2.test(actual); }; or.message = m1.message + ".or(" + m2.message + ")"; return or; }; matcher.and = function (m2) { if (!arguments.length) { throw new TypeError("Matcher expected"); } else if (!isMatcher(m2)) { m2 = match(m2); } var m1 = this; var and = sinon.create(matcher); and.test = function (actual) { return m1.test(actual) && m2.test(actual); }; and.message = m1.message + ".and(" + m2.message + ")"; return and; }; match.isMatcher = isMatcher; match.any = match(function () { return true; }, "any"); match.defined = match(function (actual) { return actual !== null && actual !== undefined; }, "defined"); match.truthy = match(function (actual) { return !!actual; }, "truthy"); match.falsy = match(function (actual) { return !actual; }, "falsy"); match.same = function (expectation) { return match(function (actual) { return expectation === actual; }, "same(" + expectation + ")"); }; match.typeOf = function (type) { assertType(type, "string", "type"); return match(function (actual) { return sinon.typeOf(actual) === type; }, "typeOf(\"" + type + "\")"); }; match.instanceOf = function (type) { assertType(type, "function", "type"); return match(function (actual) { return actual instanceof type; }, "instanceOf(" + sinon.functionName(type) + ")"); }; function createPropertyMatcher(propertyTest, messagePrefix) { return function (property, value) { assertType(property, "string", "property"); var onlyProperty = arguments.length === 1; var message = messagePrefix + "(\"" + property + "\""; if (!onlyProperty) { message += ", " + value; } message += ")"; return match(function (actual) { if (actual === undefined || actual === null || !propertyTest(actual, property)) { return false; } return onlyProperty || sinon.deepEqual(value, actual[property]); }, message); }; } match.has = createPropertyMatcher(function (actual, property) { if (typeof actual === "object") { return property in actual; } return actual[property] !== undefined; }, "has"); match.hasOwn = createPropertyMatcher(function (actual, property) { return actual.hasOwnProperty(property); }, "hasOwn"); match.bool = match.typeOf("boolean"); match.number = match.typeOf("number"); match.string = match.typeOf("string"); match.object = match.typeOf("object"); match.func = match.typeOf("function"); match.array = match.typeOf("array"); match.regexp = match.typeOf("regexp"); match.date = match.typeOf("date"); sinon.match = match; return match; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./typeOf"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/mock.js000066400000000000000000000366411276775511300233060ustar00rootroot00000000000000/** * @depend times_in_words.js * @depend util/core.js * @depend call.js * @depend extend.js * @depend match.js * @depend spy.js * @depend stub.js * @depend format.js */ /** * Mock functions. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinonGlobal) { "use strict"; function makeApi(sinon) { var push = [].push; var match = sinon.match; function mock(object) { // if (typeof console !== undefined && console.warn) { // console.warn("mock will be removed from Sinon.JS v2.0"); // } if (!object) { return sinon.expectation.create("Anonymous mock"); } return mock.create(object); } function each(collection, callback) { if (!collection) { return; } for (var i = 0, l = collection.length; i < l; i += 1) { callback(collection[i]); } } function arrayEquals(arr1, arr2, compareLength) { if (compareLength && (arr1.length !== arr2.length)) { return false; } for (var i = 0, l = arr1.length; i < l; i++) { if (!sinon.deepEqual(arr1[i], arr2[i])) { return false; } } return true; } sinon.extend(mock, { create: function create(object) { if (!object) { throw new TypeError("object is null"); } var mockObject = sinon.extend({}, mock); mockObject.object = object; delete mockObject.create; return mockObject; }, expects: function expects(method) { if (!method) { throw new TypeError("method is falsy"); } if (!this.expectations) { this.expectations = {}; this.proxies = []; } if (!this.expectations[method]) { this.expectations[method] = []; var mockObject = this; sinon.wrapMethod(this.object, method, function () { return mockObject.invokeMethod(method, this, arguments); }); push.call(this.proxies, method); } var expectation = sinon.expectation.create(method); push.call(this.expectations[method], expectation); return expectation; }, restore: function restore() { var object = this.object; each(this.proxies, function (proxy) { if (typeof object[proxy].restore === "function") { object[proxy].restore(); } }); }, verify: function verify() { var expectations = this.expectations || {}; var messages = []; var met = []; each(this.proxies, function (proxy) { each(expectations[proxy], function (expectation) { if (!expectation.met()) { push.call(messages, expectation.toString()); } else { push.call(met, expectation.toString()); } }); }); this.restore(); if (messages.length > 0) { sinon.expectation.fail(messages.concat(met).join("\n")); } else if (met.length > 0) { sinon.expectation.pass(messages.concat(met).join("\n")); } return true; }, invokeMethod: function invokeMethod(method, thisValue, args) { var expectations = this.expectations && this.expectations[method] ? this.expectations[method] : []; var expectationsWithMatchingArgs = []; var currentArgs = args || []; var i, available; for (i = 0; i < expectations.length; i += 1) { var expectedArgs = expectations[i].expectedArguments || []; if (arrayEquals(expectedArgs, currentArgs, expectations[i].expectsExactArgCount)) { expectationsWithMatchingArgs.push(expectations[i]); } } for (i = 0; i < expectationsWithMatchingArgs.length; i += 1) { if (!expectationsWithMatchingArgs[i].met() && expectationsWithMatchingArgs[i].allowsCall(thisValue, args)) { return expectationsWithMatchingArgs[i].apply(thisValue, args); } } var messages = []; var exhausted = 0; for (i = 0; i < expectationsWithMatchingArgs.length; i += 1) { if (expectationsWithMatchingArgs[i].allowsCall(thisValue, args)) { available = available || expectationsWithMatchingArgs[i]; } else { exhausted += 1; } } if (available && exhausted === 0) { return available.apply(thisValue, args); } for (i = 0; i < expectations.length; i += 1) { push.call(messages, " " + expectations[i].toString()); } messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ proxy: method, args: args })); sinon.expectation.fail(messages.join("\n")); } }); var times = sinon.timesInWords; var slice = Array.prototype.slice; function callCountInWords(callCount) { if (callCount === 0) { return "never called"; } return "called " + times(callCount); } function expectedCallCountInWords(expectation) { var min = expectation.minCalls; var max = expectation.maxCalls; if (typeof min === "number" && typeof max === "number") { var str = times(min); if (min !== max) { str = "at least " + str + " and at most " + times(max); } return str; } if (typeof min === "number") { return "at least " + times(min); } return "at most " + times(max); } function receivedMinCalls(expectation) { var hasMinLimit = typeof expectation.minCalls === "number"; return !hasMinLimit || expectation.callCount >= expectation.minCalls; } function receivedMaxCalls(expectation) { if (typeof expectation.maxCalls !== "number") { return false; } return expectation.callCount === expectation.maxCalls; } function verifyMatcher(possibleMatcher, arg) { var isMatcher = match && match.isMatcher(possibleMatcher); return isMatcher && possibleMatcher.test(arg) || true; } sinon.expectation = { minCalls: 1, maxCalls: 1, create: function create(methodName) { var expectation = sinon.extend(sinon.stub.create(), sinon.expectation); delete expectation.create; expectation.method = methodName; return expectation; }, invoke: function invoke(func, thisValue, args) { this.verifyCallAllowed(thisValue, args); return sinon.spy.invoke.apply(this, arguments); }, atLeast: function atLeast(num) { if (typeof num !== "number") { throw new TypeError("'" + num + "' is not number"); } if (!this.limitsSet) { this.maxCalls = null; this.limitsSet = true; } this.minCalls = num; return this; }, atMost: function atMost(num) { if (typeof num !== "number") { throw new TypeError("'" + num + "' is not number"); } if (!this.limitsSet) { this.minCalls = null; this.limitsSet = true; } this.maxCalls = num; return this; }, never: function never() { return this.exactly(0); }, once: function once() { return this.exactly(1); }, twice: function twice() { return this.exactly(2); }, thrice: function thrice() { return this.exactly(3); }, exactly: function exactly(num) { if (typeof num !== "number") { throw new TypeError("'" + num + "' is not a number"); } this.atLeast(num); return this.atMost(num); }, met: function met() { return !this.failed && receivedMinCalls(this); }, verifyCallAllowed: function verifyCallAllowed(thisValue, args) { if (receivedMaxCalls(this)) { this.failed = true; sinon.expectation.fail(this.method + " already called " + times(this.maxCalls)); } if ("expectedThis" in this && this.expectedThis !== thisValue) { sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " + this.expectedThis); } if (!("expectedArguments" in this)) { return; } if (!args) { sinon.expectation.fail(this.method + " received no arguments, expected " + sinon.format(this.expectedArguments)); } if (args.length < this.expectedArguments.length) { sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) + "), expected " + sinon.format(this.expectedArguments)); } if (this.expectsExactArgCount && args.length !== this.expectedArguments.length) { sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) + "), expected " + sinon.format(this.expectedArguments)); } for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { if (!verifyMatcher(this.expectedArguments[i], args[i])) { sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + ", didn't match " + this.expectedArguments.toString()); } if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + ", expected " + sinon.format(this.expectedArguments)); } } }, allowsCall: function allowsCall(thisValue, args) { if (this.met() && receivedMaxCalls(this)) { return false; } if ("expectedThis" in this && this.expectedThis !== thisValue) { return false; } if (!("expectedArguments" in this)) { return true; } args = args || []; if (args.length < this.expectedArguments.length) { return false; } if (this.expectsExactArgCount && args.length !== this.expectedArguments.length) { return false; } for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { if (!verifyMatcher(this.expectedArguments[i], args[i])) { return false; } if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { return false; } } return true; }, withArgs: function withArgs() { this.expectedArguments = slice.call(arguments); return this; }, withExactArgs: function withExactArgs() { this.withArgs.apply(this, arguments); this.expectsExactArgCount = true; return this; }, on: function on(thisValue) { this.expectedThis = thisValue; return this; }, toString: function () { var args = (this.expectedArguments || []).slice(); if (!this.expectsExactArgCount) { push.call(args, "[...]"); } var callStr = sinon.spyCall.toString.call({ proxy: this.method || "anonymous mock expectation", args: args }); var message = callStr.replace(", [...", "[, ...") + " " + expectedCallCountInWords(this); if (this.met()) { return "Expectation met: " + message; } return "Expected " + message + " (" + callCountInWords(this.callCount) + ")"; }, verify: function verify() { if (!this.met()) { sinon.expectation.fail(this.toString()); } else { sinon.expectation.pass(this.toString()); } return true; }, pass: function pass(message) { sinon.assert.pass(message); }, fail: function fail(message) { var exception = new Error(message); exception.name = "ExpectationError"; throw exception; } }; sinon.mock = mock; return mock; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./times_in_words"); require("./call"); require("./extend"); require("./match"); require("./spy"); require("./stub"); require("./format"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/sandbox.js000066400000000000000000000122121276775511300237770ustar00rootroot00000000000000/** * @depend util/core.js * @depend extend.js * @depend collection.js * @depend util/fake_timers.js * @depend util/fake_server_with_clock.js */ /** * Manages fake collections as well as fake utilities such as Sinon's * timers and fake XHR implementation in one convenient object. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinonGlobal) { "use strict"; function makeApi(sinon) { var push = [].push; function exposeValue(sandbox, config, key, value) { if (!value) { return; } if (config.injectInto && !(key in config.injectInto)) { config.injectInto[key] = value; sandbox.injectedKeys.push(key); } else { push.call(sandbox.args, value); } } function prepareSandboxFromConfig(config) { var sandbox = sinon.create(sinon.sandbox); if (config.useFakeServer) { if (typeof config.useFakeServer === "object") { sandbox.serverPrototype = config.useFakeServer; } sandbox.useFakeServer(); } if (config.useFakeTimers) { if (typeof config.useFakeTimers === "object") { sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); } else { sandbox.useFakeTimers(); } } return sandbox; } sinon.sandbox = sinon.extend(sinon.create(sinon.collection), { useFakeTimers: function useFakeTimers() { this.clock = sinon.useFakeTimers.apply(sinon, arguments); return this.add(this.clock); }, serverPrototype: sinon.fakeServer, useFakeServer: function useFakeServer() { var proto = this.serverPrototype || sinon.fakeServer; if (!proto || !proto.create) { return null; } this.server = proto.create(); return this.add(this.server); }, inject: function (obj) { sinon.collection.inject.call(this, obj); if (this.clock) { obj.clock = this.clock; } if (this.server) { obj.server = this.server; obj.requests = this.server.requests; } obj.match = sinon.match; return obj; }, restore: function () { if (arguments.length) { throw new Error("sandbox.restore() does not take any parameters. Perhaps you meant stub.restore()"); } sinon.collection.restore.apply(this, arguments); this.restoreContext(); }, restoreContext: function () { if (this.injectedKeys) { for (var i = 0, j = this.injectedKeys.length; i < j; i++) { delete this.injectInto[this.injectedKeys[i]]; } this.injectedKeys = []; } }, create: function (config) { if (!config) { return sinon.create(sinon.sandbox); } var sandbox = prepareSandboxFromConfig(config); sandbox.args = sandbox.args || []; sandbox.injectedKeys = []; sandbox.injectInto = config.injectInto; var prop, value; var exposed = sandbox.inject({}); if (config.properties) { for (var i = 0, l = config.properties.length; i < l; i++) { prop = config.properties[i]; value = exposed[prop] || prop === "sandbox" && sandbox; exposeValue(sandbox, config, prop, value); } } else { exposeValue(sandbox, config, "sandbox", value); } return sandbox; }, match: sinon.match }); sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer; return sinon.sandbox; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./util/core"); require("./extend"); require("./util/fake_server_with_clock"); require("./util/fake_timers"); require("./collection"); module.exports = makeApi(sinon); } if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/spy.js000066400000000000000000000367741276775511300231770ustar00rootroot00000000000000/** * @depend times_in_words.js * @depend util/core.js * @depend extend.js * @depend call.js * @depend format.js */ /** * Spy functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinonGlobal) { "use strict"; function makeApi(sinon) { var push = Array.prototype.push; var slice = Array.prototype.slice; var callId = 0; function spy(object, property, types) { if (!property && typeof object === "function") { return spy.create(object); } if (!object && !property) { return spy.create(function () { }); } if (types) { var methodDesc = sinon.getPropertyDescriptor(object, property); for (var i = 0; i < types.length; i++) { methodDesc[types[i]] = spy.create(methodDesc[types[i]]); } return sinon.wrapMethod(object, property, methodDesc); } return sinon.wrapMethod(object, property, spy.create(object[property])); } function matchingFake(fakes, args, strict) { if (!fakes) { return undefined; } for (var i = 0, l = fakes.length; i < l; i++) { if (fakes[i].matches(args, strict)) { return fakes[i]; } } } function incrementCallCount() { this.called = true; this.callCount += 1; this.notCalled = false; this.calledOnce = this.callCount === 1; this.calledTwice = this.callCount === 2; this.calledThrice = this.callCount === 3; } function createCallProperties() { this.firstCall = this.getCall(0); this.secondCall = this.getCall(1); this.thirdCall = this.getCall(2); this.lastCall = this.getCall(this.callCount - 1); } var vars = "a,b,c,d,e,f,g,h,i,j,k,l"; function createProxy(func, proxyLength) { // Retain the function length: var p; if (proxyLength) { eval("p = (function proxy(" + vars.substring(0, proxyLength * 2 - 1) + // eslint-disable-line no-eval ") { return p.invoke(func, this, slice.call(arguments)); });"); } else { p = function proxy() { return p.invoke(func, this, slice.call(arguments)); }; } p.isSinonProxy = true; return p; } var uuid = 0; // Public API var spyApi = { reset: function () { if (this.invoking) { var err = new Error("Cannot reset Sinon function while invoking it. " + "Move the call to .reset outside of the callback."); err.name = "InvalidResetException"; throw err; } this.called = false; this.notCalled = true; this.calledOnce = false; this.calledTwice = false; this.calledThrice = false; this.callCount = 0; this.firstCall = null; this.secondCall = null; this.thirdCall = null; this.lastCall = null; this.args = []; this.returnValues = []; this.thisValues = []; this.exceptions = []; this.callIds = []; this.stacks = []; if (this.fakes) { for (var i = 0; i < this.fakes.length; i++) { this.fakes[i].reset(); } } return this; }, create: function create(func, spyLength) { var name; if (typeof func !== "function") { func = function () { }; } else { name = sinon.functionName(func); } if (!spyLength) { spyLength = func.length; } var proxy = createProxy(func, spyLength); sinon.extend(proxy, spy); delete proxy.create; sinon.extend(proxy, func); proxy.reset(); proxy.prototype = func.prototype; proxy.displayName = name || "spy"; proxy.toString = sinon.functionToString; proxy.instantiateFake = sinon.spy.create; proxy.id = "spy#" + uuid++; return proxy; }, invoke: function invoke(func, thisValue, args) { var matching = matchingFake(this.fakes, args); var exception, returnValue; incrementCallCount.call(this); push.call(this.thisValues, thisValue); push.call(this.args, args); push.call(this.callIds, callId++); // Make call properties available from within the spied function: createCallProperties.call(this); try { this.invoking = true; if (matching) { returnValue = matching.invoke(func, thisValue, args); } else { returnValue = (this.func || func).apply(thisValue, args); } var thisCall = this.getCall(this.callCount - 1); if (thisCall.calledWithNew() && typeof returnValue !== "object") { returnValue = thisValue; } } catch (e) { exception = e; } finally { delete this.invoking; } push.call(this.exceptions, exception); push.call(this.returnValues, returnValue); push.call(this.stacks, new Error().stack); // Make return value and exception available in the calls: createCallProperties.call(this); if (exception !== undefined) { throw exception; } return returnValue; }, named: function named(name) { this.displayName = name; return this; }, getCall: function getCall(i) { if (i < 0 || i >= this.callCount) { return null; } return sinon.spyCall(this, this.thisValues[i], this.args[i], this.returnValues[i], this.exceptions[i], this.callIds[i], this.stacks[i]); }, getCalls: function () { var calls = []; var i; for (i = 0; i < this.callCount; i++) { calls.push(this.getCall(i)); } return calls; }, calledBefore: function calledBefore(spyFn) { if (!this.called) { return false; } if (!spyFn.called) { return true; } return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1]; }, calledAfter: function calledAfter(spyFn) { if (!this.called || !spyFn.called) { return false; } return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1]; }, withArgs: function () { var args = slice.call(arguments); if (this.fakes) { var match = matchingFake(this.fakes, args, true); if (match) { return match; } } else { this.fakes = []; } var original = this; var fake = this.instantiateFake(); fake.matchingAguments = args; fake.parent = this; push.call(this.fakes, fake); fake.withArgs = function () { return original.withArgs.apply(original, arguments); }; for (var i = 0; i < this.args.length; i++) { if (fake.matches(this.args[i])) { incrementCallCount.call(fake); push.call(fake.thisValues, this.thisValues[i]); push.call(fake.args, this.args[i]); push.call(fake.returnValues, this.returnValues[i]); push.call(fake.exceptions, this.exceptions[i]); push.call(fake.callIds, this.callIds[i]); } } createCallProperties.call(fake); return fake; }, matches: function (args, strict) { var margs = this.matchingAguments; if (margs.length <= args.length && sinon.deepEqual(margs, args.slice(0, margs.length))) { return !strict || margs.length === args.length; } }, printf: function (format) { var spyInstance = this; var args = slice.call(arguments, 1); var formatter; return (format || "").replace(/%(.)/g, function (match, specifyer) { formatter = spyApi.formatters[specifyer]; if (typeof formatter === "function") { return formatter.call(null, spyInstance, args); } else if (!isNaN(parseInt(specifyer, 10))) { return sinon.format(args[specifyer - 1]); } return "%" + specifyer; }); } }; function delegateToCalls(method, matchAny, actual, notCalled) { spyApi[method] = function () { if (!this.called) { if (notCalled) { return notCalled.apply(this, arguments); } return false; } var currentCall; var matches = 0; for (var i = 0, l = this.callCount; i < l; i += 1) { currentCall = this.getCall(i); if (currentCall[actual || method].apply(currentCall, arguments)) { matches += 1; if (matchAny) { return true; } } } return matches === this.callCount; }; } delegateToCalls("calledOn", true); delegateToCalls("alwaysCalledOn", false, "calledOn"); delegateToCalls("calledWith", true); delegateToCalls("calledWithMatch", true); delegateToCalls("alwaysCalledWith", false, "calledWith"); delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch"); delegateToCalls("calledWithExactly", true); delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly"); delegateToCalls("neverCalledWith", false, "notCalledWith", function () { return true; }); delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch", function () { return true; }); delegateToCalls("threw", true); delegateToCalls("alwaysThrew", false, "threw"); delegateToCalls("returned", true); delegateToCalls("alwaysReturned", false, "returned"); delegateToCalls("calledWithNew", true); delegateToCalls("alwaysCalledWithNew", false, "calledWithNew"); delegateToCalls("callArg", false, "callArgWith", function () { throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); }); spyApi.callArgWith = spyApi.callArg; delegateToCalls("callArgOn", false, "callArgOnWith", function () { throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); }); spyApi.callArgOnWith = spyApi.callArgOn; delegateToCalls("yield", false, "yield", function () { throw new Error(this.toString() + " cannot yield since it was not yet invoked."); }); // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode. spyApi.invokeCallback = spyApi.yield; delegateToCalls("yieldOn", false, "yieldOn", function () { throw new Error(this.toString() + " cannot yield since it was not yet invoked."); }); delegateToCalls("yieldTo", false, "yieldTo", function (property) { throw new Error(this.toString() + " cannot yield to '" + property + "' since it was not yet invoked."); }); delegateToCalls("yieldToOn", false, "yieldToOn", function (property) { throw new Error(this.toString() + " cannot yield to '" + property + "' since it was not yet invoked."); }); spyApi.formatters = { c: function (spyInstance) { return sinon.timesInWords(spyInstance.callCount); }, n: function (spyInstance) { return spyInstance.toString(); }, C: function (spyInstance) { var calls = []; for (var i = 0, l = spyInstance.callCount; i < l; ++i) { var stringifiedCall = " " + spyInstance.getCall(i).toString(); if (/\n/.test(calls[i - 1])) { stringifiedCall = "\n" + stringifiedCall; } push.call(calls, stringifiedCall); } return calls.length > 0 ? "\n" + calls.join("\n") : ""; }, t: function (spyInstance) { var objects = []; for (var i = 0, l = spyInstance.callCount; i < l; ++i) { push.call(objects, sinon.format(spyInstance.thisValues[i])); } return objects.join(", "); }, "*": function (spyInstance, args) { var formatted = []; for (var i = 0, l = args.length; i < l; ++i) { push.call(formatted, sinon.format(args[i])); } return formatted.join(", "); } }; sinon.extend(spy, spyApi); spy.spyCall = sinon.spyCall; sinon.spy = spy; return spy; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var core = require("./util/core"); require("./call"); require("./extend"); require("./times_in_words"); require("./format"); module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/stub.js000066400000000000000000000145151276775511300233260ustar00rootroot00000000000000/** * @depend util/core.js * @depend extend.js * @depend spy.js * @depend behavior.js * @depend walk.js */ /** * Stub functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinonGlobal) { "use strict"; function makeApi(sinon) { function stub(object, property, func) { if (!!func && typeof func !== "function" && typeof func !== "object") { throw new TypeError("Custom stub should be a function or a property descriptor"); } var wrapper; if (func) { if (typeof func === "function") { wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; } else { wrapper = func; if (sinon.spy && sinon.spy.create) { var types = sinon.objectKeys(wrapper); for (var i = 0; i < types.length; i++) { wrapper[types[i]] = sinon.spy.create(wrapper[types[i]]); } } } } else { var stubLength = 0; if (typeof object === "object" && typeof object[property] === "function") { stubLength = object[property].length; } wrapper = stub.create(stubLength); } if (!object && typeof property === "undefined") { return sinon.stub.create(); } if (typeof property === "undefined" && typeof object === "object") { sinon.walk(object || {}, function (value, prop, propOwner) { // we don't want to stub things like toString(), valueOf(), etc. so we only stub if the object // is not Object.prototype if ( propOwner !== Object.prototype && prop !== "constructor" && typeof sinon.getPropertyDescriptor(propOwner, prop).value === "function" ) { stub(object, prop); } }); return object; } return sinon.wrapMethod(object, property, wrapper); } /*eslint-disable no-use-before-define*/ function getParentBehaviour(stubInstance) { return (stubInstance.parent && getCurrentBehavior(stubInstance.parent)); } function getDefaultBehavior(stubInstance) { return stubInstance.defaultBehavior || getParentBehaviour(stubInstance) || sinon.behavior.create(stubInstance); } function getCurrentBehavior(stubInstance) { var behavior = stubInstance.behaviors[stubInstance.callCount - 1]; return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stubInstance); } /*eslint-enable no-use-before-define*/ var uuid = 0; var proto = { create: function create(stubLength) { var functionStub = function () { return getCurrentBehavior(functionStub).invoke(this, arguments); }; functionStub.id = "stub#" + uuid++; var orig = functionStub; functionStub = sinon.spy.create(functionStub, stubLength); functionStub.func = orig; sinon.extend(functionStub, stub); functionStub.instantiateFake = sinon.stub.create; functionStub.displayName = "stub"; functionStub.toString = sinon.functionToString; functionStub.defaultBehavior = null; functionStub.behaviors = []; return functionStub; }, resetBehavior: function () { var i; this.defaultBehavior = null; this.behaviors = []; delete this.returnValue; delete this.returnArgAt; this.returnThis = false; if (this.fakes) { for (i = 0; i < this.fakes.length; i++) { this.fakes[i].resetBehavior(); } } }, onCall: function onCall(index) { if (!this.behaviors[index]) { this.behaviors[index] = sinon.behavior.create(this); } return this.behaviors[index]; }, onFirstCall: function onFirstCall() { return this.onCall(0); }, onSecondCall: function onSecondCall() { return this.onCall(1); }, onThirdCall: function onThirdCall() { return this.onCall(2); } }; function createBehavior(behaviorMethod) { return function () { this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this); this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments); return this; }; } for (var method in sinon.behavior) { if (sinon.behavior.hasOwnProperty(method) && !proto.hasOwnProperty(method) && method !== "create" && method !== "withArgs" && method !== "invoke") { proto[method] = createBehavior(method); } } sinon.extend(stub, proto); sinon.stub = stub; return stub; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var core = require("./util/core"); require("./behavior"); require("./spy"); require("./extend"); module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/test.js000066400000000000000000000060401276775511300233220ustar00rootroot00000000000000/** * @depend util/core.js * @depend sandbox.js */ /** * Test function, sandboxes fakes * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinonGlobal) { "use strict"; function makeApi(sinon) { var slice = Array.prototype.slice; function test(callback) { var type = typeof callback; if (type !== "function") { throw new TypeError("sinon.test needs to wrap a test function, got " + type); } function sinonSandboxedTest() { var config = sinon.getConfig(sinon.config); config.injectInto = config.injectIntoThis && this || config.injectInto; var sandbox = sinon.sandbox.create(config); var args = slice.call(arguments); var oldDone = args.length && args[args.length - 1]; var exception, result; if (typeof oldDone === "function") { args[args.length - 1] = function sinonDone(res) { if (res) { sandbox.restore(); } else { sandbox.verifyAndRestore(); } oldDone(res); }; } try { result = callback.apply(this, args.concat(sandbox.args)); } catch (e) { exception = e; } if (typeof exception !== "undefined") { sandbox.restore(); throw exception; } else if (typeof oldDone !== "function") { sandbox.verifyAndRestore(); } return result; } if (callback.length) { return function sinonAsyncSandboxedTest(done) { // eslint-disable-line no-unused-vars return sinonSandboxedTest.apply(this, arguments); }; } return sinonSandboxedTest; } test.config = { injectIntoThis: true, injectInto: null, properties: ["spy", "stub", "mock", "clock", "server", "requests"], useFakeTimers: true, useFakeServer: true }; sinon.test = test; return test; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var core = require("./util/core"); require("./sandbox"); module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else if (sinonGlobal) { makeApi(sinonGlobal); } }(typeof sinon === "object" && sinon || null)); // eslint-disable-line no-undef sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/test_case.js000066400000000000000000000053641276775511300243250ustar00rootroot00000000000000/** * @depend util/core.js * @depend test.js */ /** * Test case, sandboxes all test functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinonGlobal) { "use strict"; function createTest(property, setUp, tearDown) { return function () { if (setUp) { setUp.apply(this, arguments); } var exception, result; try { result = property.apply(this, arguments); } catch (e) { exception = e; } if (tearDown) { tearDown.apply(this, arguments); } if (exception) { throw exception; } return result; }; } function makeApi(sinon) { function testCase(tests, prefix) { if (!tests || typeof tests !== "object") { throw new TypeError("sinon.testCase needs an object with test functions"); } prefix = prefix || "test"; var rPrefix = new RegExp("^" + prefix); var methods = {}; var setUp = tests.setUp; var tearDown = tests.tearDown; var testName, property, method; for (testName in tests) { if (tests.hasOwnProperty(testName) && !/^(setUp|tearDown)$/.test(testName)) { property = tests[testName]; if (typeof property === "function" && rPrefix.test(testName)) { method = property; if (setUp || tearDown) { method = createTest(property, setUp, tearDown); } methods[testName] = sinon.test(method); } else { methods[testName] = tests[testName]; } } } return methods; } sinon.testCase = testCase; return testCase; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var core = require("./util/core"); require("./test"); module.exports = makeApi(core); } if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/times_in_words.js000066400000000000000000000022541276775511300253730ustar00rootroot00000000000000/** * @depend util/core.js */ (function (sinonGlobal) { "use strict"; function makeApi(sinon) { function timesInWords(count) { switch (count) { case 1: return "once"; case 2: return "twice"; case 3: return "thrice"; default: return (count || 0) + " times"; } } sinon.timesInWords = timesInWords; return sinon.timesInWords; } function loadDependencies(require, exports, module) { var core = require("./util/core"); module.exports = makeApi(core); } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/typeOf.js000066400000000000000000000024501276775511300236120ustar00rootroot00000000000000/** * @depend util/core.js */ /** * Format functions * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2014 Christian Johansen */ (function (sinonGlobal) { "use strict"; function makeApi(sinon) { function typeOf(value) { if (value === null) { return "null"; } else if (value === undefined) { return "undefined"; } var string = Object.prototype.toString.call(value); return string.substring(8, string.length - 1).toLowerCase(); } sinon.typeOf = typeOf; return sinon.typeOf; } function loadDependencies(require, exports, module) { var core = require("./util/core"); module.exports = makeApi(core); } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/util/000077500000000000000000000000001276775511300227625ustar00rootroot00000000000000sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/util/core.js000066400000000000000000000333131276775511300242530ustar00rootroot00000000000000/** * @depend ../../sinon.js */ /** * Sinon core utilities. For internal use only. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinonGlobal) { "use strict"; var div = typeof document !== "undefined" && document.createElement("div"); var hasOwn = Object.prototype.hasOwnProperty; function isDOMNode(obj) { var success = false; try { obj.appendChild(div); success = div.parentNode === obj; } catch (e) { return false; } finally { try { obj.removeChild(div); } catch (e) { // Remove failed, not much we can do about that } } return success; } function isElement(obj) { return div && obj && obj.nodeType === 1 && isDOMNode(obj); } function isFunction(obj) { return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply); } function isReallyNaN(val) { return typeof val === "number" && isNaN(val); } function mirrorProperties(target, source) { for (var prop in source) { if (!hasOwn.call(target, prop)) { target[prop] = source[prop]; } } } function isRestorable(obj) { return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon; } // Cheap way to detect if we have ES5 support. var hasES5Support = "keys" in Object; function makeApi(sinon) { sinon.wrapMethod = function wrapMethod(object, property, method) { if (!object) { throw new TypeError("Should wrap property of object"); } if (typeof method !== "function" && typeof method !== "object") { throw new TypeError("Method wrapper should be a function or a property descriptor"); } function checkWrappedMethod(wrappedMethod) { var error; if (!isFunction(wrappedMethod)) { error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + property + " as function"); } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) { error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); } else if (wrappedMethod.calledBefore) { var verb = wrappedMethod.returns ? "stubbed" : "spied on"; error = new TypeError("Attempted to wrap " + property + " which is already " + verb); } if (error) { if (wrappedMethod && wrappedMethod.stackTrace) { error.stack += "\n--------------\n" + wrappedMethod.stackTrace; } throw error; } } var error, wrappedMethod, i; function simplePropertyAssignment() { wrappedMethod = object[property]; checkWrappedMethod(wrappedMethod); object[property] = method; method.displayName = property; } // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem // when using hasOwn.call on objects from other frames. var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property); if (hasES5Support) { var methodDesc = (typeof method === "function") ? {value: method} : method; var wrappedMethodDesc = sinon.getPropertyDescriptor(object, property); if (!wrappedMethodDesc) { error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + property + " as function"); } else if (wrappedMethodDesc.restore && wrappedMethodDesc.restore.sinon) { error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); } if (error) { if (wrappedMethodDesc && wrappedMethodDesc.stackTrace) { error.stack += "\n--------------\n" + wrappedMethodDesc.stackTrace; } throw error; } var types = sinon.objectKeys(methodDesc); for (i = 0; i < types.length; i++) { wrappedMethod = wrappedMethodDesc[types[i]]; checkWrappedMethod(wrappedMethod); } mirrorProperties(methodDesc, wrappedMethodDesc); for (i = 0; i < types.length; i++) { mirrorProperties(methodDesc[types[i]], wrappedMethodDesc[types[i]]); } Object.defineProperty(object, property, methodDesc); // catch failing assignment // this is the converse of the check in `.restore` below if ( typeof method === "function" && object[property] !== method ) { // correct any wrongdoings caused by the defineProperty call above, // such as adding new items (if object was a Storage object) delete object[property]; simplePropertyAssignment(); } } else { simplePropertyAssignment(); } method.displayName = property; // Set up a stack trace which can be used later to find what line of // code the original method was created on. method.stackTrace = (new Error("Stack Trace for original")).stack; method.restore = function () { // For prototype properties try to reset by delete first. // If this fails (ex: localStorage on mobile safari) then force a reset // via direct assignment. if (!owned) { // In some cases `delete` may throw an error try { delete object[property]; } catch (e) {} // eslint-disable-line no-empty // For native code functions `delete` fails without throwing an error // on Chrome < 43, PhantomJS, etc. } else if (hasES5Support) { Object.defineProperty(object, property, wrappedMethodDesc); } // Use strict equality comparison to check failures then force a reset // via direct assignment. if (object[property] === method) { object[property] = wrappedMethod; } }; method.restore.sinon = true; if (!hasES5Support) { mirrorProperties(method, wrappedMethod); } return method; }; sinon.create = function create(proto) { var F = function () {}; F.prototype = proto; return new F(); }; sinon.deepEqual = function deepEqual(a, b) { if (sinon.match && sinon.match.isMatcher(a)) { return a.test(b); } if (typeof a !== "object" || typeof b !== "object") { return isReallyNaN(a) && isReallyNaN(b) || a === b; } if (isElement(a) || isElement(b)) { return a === b; } if (a === b) { return true; } if ((a === null && b !== null) || (a !== null && b === null)) { return false; } if (a instanceof RegExp && b instanceof RegExp) { return (a.source === b.source) && (a.global === b.global) && (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline); } var aString = Object.prototype.toString.call(a); if (aString !== Object.prototype.toString.call(b)) { return false; } if (aString === "[object Date]") { return a.valueOf() === b.valueOf(); } var prop; var aLength = 0; var bLength = 0; if (aString === "[object Array]" && a.length !== b.length) { return false; } for (prop in a) { if (hasOwn.call(a, prop)) { aLength += 1; if (!(prop in b)) { return false; } if (!deepEqual(a[prop], b[prop])) { return false; } } } for (prop in b) { if (hasOwn.call(b, prop)) { bLength += 1; } } return aLength === bLength; }; sinon.functionName = function functionName(func) { var name = func.displayName || func.name; // Use function decomposition as a last resort to get function // name. Does not rely on function decomposition to work - if it // doesn't debugging will be slightly less informative // (i.e. toString will say 'spy' rather than 'myFunc'). if (!name) { var matches = func.toString().match(/function ([^\s\(]+)/); name = matches && matches[1]; } return name; }; sinon.functionToString = function toString() { if (this.getCall && this.callCount) { var thisValue, prop; var i = this.callCount; while (i--) { thisValue = this.getCall(i).thisValue; for (prop in thisValue) { if (thisValue[prop] === this) { return prop; } } } } return this.displayName || "sinon fake"; }; sinon.objectKeys = function objectKeys(obj) { if (obj !== Object(obj)) { throw new TypeError("sinon.objectKeys called on a non-object"); } var keys = []; var key; for (key in obj) { if (hasOwn.call(obj, key)) { keys.push(key); } } return keys; }; sinon.getPropertyDescriptor = function getPropertyDescriptor(object, property) { var proto = object; var descriptor; while (proto && !(descriptor = Object.getOwnPropertyDescriptor(proto, property))) { proto = Object.getPrototypeOf(proto); } return descriptor; }; sinon.getConfig = function (custom) { var config = {}; custom = custom || {}; var defaults = sinon.defaultConfig; for (var prop in defaults) { if (defaults.hasOwnProperty(prop)) { config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop]; } } return config; }; sinon.defaultConfig = { injectIntoThis: true, injectInto: null, properties: ["spy", "stub", "mock", "clock", "server", "requests"], useFakeTimers: true, useFakeServer: true }; sinon.timesInWords = function timesInWords(count) { return count === 1 && "once" || count === 2 && "twice" || count === 3 && "thrice" || (count || 0) + " times"; }; sinon.calledInOrder = function (spies) { for (var i = 1, l = spies.length; i < l; i++) { if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) { return false; } } return true; }; sinon.orderByFirstCall = function (spies) { return spies.sort(function (a, b) { // uuid, won't ever be equal var aCall = a.getCall(0); var bCall = b.getCall(0); var aId = aCall && aCall.callId || -1; var bId = bCall && bCall.callId || -1; return aId < bId ? -1 : 1; }); }; sinon.createStubInstance = function (constructor) { if (typeof constructor !== "function") { throw new TypeError("The constructor should be a function."); } return sinon.stub(sinon.create(constructor.prototype)); }; sinon.restore = function (object) { if (object !== null && typeof object === "object") { for (var prop in object) { if (isRestorable(object[prop])) { object[prop].restore(); } } } else if (isRestorable(object)) { object.restore(); } }; return sinon; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports) { makeApi(exports); } if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/util/event.js000066400000000000000000000073031276775511300244440ustar00rootroot00000000000000/** * Minimal Event interface implementation * * Original implementation by Sven Fuchs: https://gist.github.com/995028 * Modifications and tests by Christian Johansen. * * @author Sven Fuchs (svenfuchs@artweb-design.de) * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2011 Sven Fuchs, Christian Johansen */ if (typeof sinon === "undefined") { this.sinon = {}; } (function () { "use strict"; var push = [].push; function makeApi(sinon) { sinon.Event = function Event(type, bubbles, cancelable, target) { this.initEvent(type, bubbles, cancelable, target); }; sinon.Event.prototype = { initEvent: function (type, bubbles, cancelable, target) { this.type = type; this.bubbles = bubbles; this.cancelable = cancelable; this.target = target; }, stopPropagation: function () {}, preventDefault: function () { this.defaultPrevented = true; } }; sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) { this.initEvent(type, false, false, target); this.loaded = typeof progressEventRaw.loaded === "number" ? progressEventRaw.loaded : null; this.total = typeof progressEventRaw.total === "number" ? progressEventRaw.total : null; this.lengthComputable = !!progressEventRaw.total; }; sinon.ProgressEvent.prototype = new sinon.Event(); sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent; sinon.CustomEvent = function CustomEvent(type, customData, target) { this.initEvent(type, false, false, target); this.detail = customData.detail || null; }; sinon.CustomEvent.prototype = new sinon.Event(); sinon.CustomEvent.prototype.constructor = sinon.CustomEvent; sinon.EventTarget = { addEventListener: function addEventListener(event, listener) { this.eventListeners = this.eventListeners || {}; this.eventListeners[event] = this.eventListeners[event] || []; push.call(this.eventListeners[event], listener); }, removeEventListener: function removeEventListener(event, listener) { var listeners = this.eventListeners && this.eventListeners[event] || []; for (var i = 0, l = listeners.length; i < l; ++i) { if (listeners[i] === listener) { return listeners.splice(i, 1); } } }, dispatchEvent: function dispatchEvent(event) { var type = event.type; var listeners = this.eventListeners && this.eventListeners[type] || []; for (var i = 0; i < listeners.length; i++) { if (typeof listeners[i] === "function") { listeners[i].call(this, event); } else { listeners[i].handleEvent(event); } } return !!event.defaultPrevented; } }; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require) { var sinon = require("./core"); makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require); } else { makeApi(sinon); // eslint-disable-line no-undef } }()); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/util/fake_server.js000066400000000000000000000200561276775511300256170ustar00rootroot00000000000000/** * @depend fake_xdomain_request.js * @depend fake_xml_http_request.js * @depend ../format.js * @depend ../log_error.js */ /** * The Sinon "server" mimics a web server that receives requests from * sinon.FakeXMLHttpRequest and provides an API to respond to those requests, * both synchronously and asynchronously. To respond synchronuously, canned * answers have to be provided upfront. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function () { "use strict"; var push = [].push; function responseArray(handler) { var response = handler; if (Object.prototype.toString.call(handler) !== "[object Array]") { response = [200, {}, handler]; } if (typeof response[2] !== "string") { throw new TypeError("Fake server response body should be string, but was " + typeof response[2]); } return response; } var wloc = typeof window !== "undefined" ? window.location : {}; var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); function matchOne(response, reqMethod, reqUrl) { var rmeth = response.method; var matchMethod = !rmeth || rmeth.toLowerCase() === reqMethod.toLowerCase(); var url = response.url; var matchUrl = !url || url === reqUrl || (typeof url.test === "function" && url.test(reqUrl)); return matchMethod && matchUrl; } function match(response, request) { var requestUrl = request.url; if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) { requestUrl = requestUrl.replace(rCurrLoc, ""); } if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { if (typeof response.response === "function") { var ru = response.url; var args = [request].concat(ru && typeof ru.exec === "function" ? ru.exec(requestUrl).slice(1) : []); return response.response.apply(response, args); } return true; } return false; } function makeApi(sinon) { sinon.fakeServer = { create: function (config) { var server = sinon.create(this); server.configure(config); if (!sinon.xhr.supportsCORS) { this.xhr = sinon.useFakeXDomainRequest(); } else { this.xhr = sinon.useFakeXMLHttpRequest(); } server.requests = []; this.xhr.onCreate = function (xhrObj) { server.addRequest(xhrObj); }; return server; }, configure: function (config) { var whitelist = { "autoRespond": true, "autoRespondAfter": true, "respondImmediately": true, "fakeHTTPMethods": true }; var setting; config = config || {}; for (setting in config) { if (whitelist.hasOwnProperty(setting) && config.hasOwnProperty(setting)) { this[setting] = config[setting]; } } }, addRequest: function addRequest(xhrObj) { var server = this; push.call(this.requests, xhrObj); xhrObj.onSend = function () { server.handleRequest(this); if (server.respondImmediately) { server.respond(); } else if (server.autoRespond && !server.responding) { setTimeout(function () { server.responding = false; server.respond(); }, server.autoRespondAfter || 10); server.responding = true; } }; }, getHTTPMethod: function getHTTPMethod(request) { if (this.fakeHTTPMethods && /post/i.test(request.method)) { var matches = (request.requestBody || "").match(/_method=([^\b;]+)/); return matches ? matches[1] : request.method; } return request.method; }, handleRequest: function handleRequest(xhr) { if (xhr.async) { if (!this.queue) { this.queue = []; } push.call(this.queue, xhr); } else { this.processRequest(xhr); } }, log: function log(response, request) { var str; str = "Request:\n" + sinon.format(request) + "\n\n"; str += "Response:\n" + sinon.format(response) + "\n\n"; sinon.log(str); }, respondWith: function respondWith(method, url, body) { if (arguments.length === 1 && typeof method !== "function") { this.response = responseArray(method); return; } if (!this.responses) { this.responses = []; } if (arguments.length === 1) { body = method; url = method = null; } if (arguments.length === 2) { body = url; url = method; method = null; } push.call(this.responses, { method: method, url: url, response: typeof body === "function" ? body : responseArray(body) }); }, respond: function respond() { if (arguments.length > 0) { this.respondWith.apply(this, arguments); } var queue = this.queue || []; var requests = queue.splice(0, queue.length); for (var i = 0; i < requests.length; i++) { this.processRequest(requests[i]); } }, processRequest: function processRequest(request) { try { if (request.aborted) { return; } var response = this.response || [404, {}, ""]; if (this.responses) { for (var l = this.responses.length, i = l - 1; i >= 0; i--) { if (match.call(this, this.responses[i], request)) { response = this.responses[i].response; break; } } } if (request.readyState !== 4) { this.log(response, request); request.respond(response[0], response[1], response[2]); } } catch (e) { sinon.logError("Fake server request processing", e); } }, restore: function restore() { return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments); } }; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./core"); require("./fake_xdomain_request"); require("./fake_xml_http_request"); require("../format"); makeApi(sinon); module.exports = sinon; } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else { makeApi(sinon); // eslint-disable-line no-undef } }()); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/util/fake_server_with_clock.js000066400000000000000000000064211276775511300300250ustar00rootroot00000000000000/** * @depend fake_server.js * @depend fake_timers.js */ /** * Add-on for sinon.fakeServer that automatically handles a fake timer along with * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead, * it polls the object for completion with setInterval. Dispite the direct * motivation, there is nothing jQuery-specific in this file, so it can be used * in any environment where the ajax implementation depends on setInterval or * setTimeout. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function () { "use strict"; function makeApi(sinon) { function Server() {} Server.prototype = sinon.fakeServer; sinon.fakeServerWithClock = new Server(); sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { if (xhr.async) { if (typeof setTimeout.clock === "object") { this.clock = setTimeout.clock; } else { this.clock = sinon.useFakeTimers(); this.resetClock = true; } if (!this.longestTimeout) { var clockSetTimeout = this.clock.setTimeout; var clockSetInterval = this.clock.setInterval; var server = this; this.clock.setTimeout = function (fn, timeout) { server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); return clockSetTimeout.apply(this, arguments); }; this.clock.setInterval = function (fn, timeout) { server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); return clockSetInterval.apply(this, arguments); }; } } return sinon.fakeServer.addRequest.call(this, xhr); }; sinon.fakeServerWithClock.respond = function respond() { var returnVal = sinon.fakeServer.respond.apply(this, arguments); if (this.clock) { this.clock.tick(this.longestTimeout || 0); this.longestTimeout = 0; if (this.resetClock) { this.clock.restore(); this.resetClock = false; } } return returnVal; }; sinon.fakeServerWithClock.restore = function restore() { if (this.clock) { this.clock.restore(); } return sinon.fakeServer.restore.apply(this, arguments); }; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require) { var sinon = require("./core"); require("./fake_server"); require("./fake_timers"); makeApi(sinon); } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require); } else { makeApi(sinon); // eslint-disable-line no-undef } }()); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/util/fake_timers.js000066400000000000000000000037051276775511300256160ustar00rootroot00000000000000/** * Fake timer API * setTimeout * setInterval * clearTimeout * clearInterval * tick * reset * Date * * Inspired by jsUnitMockTimeOut from JsUnit * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function () { "use strict"; function makeApi(s, lol) { /*global lolex */ var llx = typeof lolex !== "undefined" ? lolex : lol; s.useFakeTimers = function () { var now; var methods = Array.prototype.slice.call(arguments); if (typeof methods[0] === "string") { now = 0; } else { now = methods.shift(); } var clock = llx.install(now || 0, methods); clock.restore = clock.uninstall; return clock; }; s.clock = { create: function (now) { return llx.createClock(now); } }; s.timers = { setTimeout: setTimeout, clearTimeout: clearTimeout, setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate : undefined), setInterval: setInterval, clearInterval: clearInterval, Date: Date }; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, epxorts, module, lolex) { var core = require("./core"); makeApi(core, lolex); module.exports = core; } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module, require("lolex")); } else { makeApi(sinon); // eslint-disable-line no-undef } }()); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/util/fake_xdomain_request.js000066400000000000000000000174061276775511300275250ustar00rootroot00000000000000/** * @depend core.js * @depend ../extend.js * @depend event.js * @depend ../log_error.js */ /** * Fake XDomainRequest object */ /** * Returns the global to prevent assigning values to 'this' when this is undefined. * This can occur when files are interpreted by node in strict mode. * @private */ function getGlobal() { "use strict"; return typeof window !== "undefined" ? window : global; } if (typeof sinon === "undefined") { if (typeof this === "undefined") { getGlobal().sinon = {}; } else { this.sinon = {}; } } // wrapper for global (function (global) { "use strict"; var xdr = { XDomainRequest: global.XDomainRequest }; xdr.GlobalXDomainRequest = global.XDomainRequest; xdr.supportsXDR = typeof xdr.GlobalXDomainRequest !== "undefined"; xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false; function makeApi(sinon) { sinon.xdr = xdr; function FakeXDomainRequest() { this.readyState = FakeXDomainRequest.UNSENT; this.requestBody = null; this.requestHeaders = {}; this.status = 0; this.timeout = null; if (typeof FakeXDomainRequest.onCreate === "function") { FakeXDomainRequest.onCreate(this); } } function verifyState(x) { if (x.readyState !== FakeXDomainRequest.OPENED) { throw new Error("INVALID_STATE_ERR"); } if (x.sendFlag) { throw new Error("INVALID_STATE_ERR"); } } function verifyRequestSent(x) { if (x.readyState === FakeXDomainRequest.UNSENT) { throw new Error("Request not sent"); } if (x.readyState === FakeXDomainRequest.DONE) { throw new Error("Request done"); } } function verifyResponseBodyType(body) { if (typeof body !== "string") { var error = new Error("Attempted to respond to fake XDomainRequest with " + body + ", which is not a string."); error.name = "InvalidBodyException"; throw error; } } sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, { open: function open(method, url) { this.method = method; this.url = url; this.responseText = null; this.sendFlag = false; this.readyStateChange(FakeXDomainRequest.OPENED); }, readyStateChange: function readyStateChange(state) { this.readyState = state; var eventName = ""; switch (this.readyState) { case FakeXDomainRequest.UNSENT: break; case FakeXDomainRequest.OPENED: break; case FakeXDomainRequest.LOADING: if (this.sendFlag) { //raise the progress event eventName = "onprogress"; } break; case FakeXDomainRequest.DONE: if (this.isTimeout) { eventName = "ontimeout"; } else if (this.errorFlag || (this.status < 200 || this.status > 299)) { eventName = "onerror"; } else { eventName = "onload"; } break; } // raising event (if defined) if (eventName) { if (typeof this[eventName] === "function") { try { this[eventName](); } catch (e) { sinon.logError("Fake XHR " + eventName + " handler", e); } } } }, send: function send(data) { verifyState(this); if (!/^(get|head)$/i.test(this.method)) { this.requestBody = data; } this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; this.errorFlag = false; this.sendFlag = true; this.readyStateChange(FakeXDomainRequest.OPENED); if (typeof this.onSend === "function") { this.onSend(this); } }, abort: function abort() { this.aborted = true; this.responseText = null; this.errorFlag = true; if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) { this.readyStateChange(sinon.FakeXDomainRequest.DONE); this.sendFlag = false; } }, setResponseBody: function setResponseBody(body) { verifyRequestSent(this); verifyResponseBodyType(body); var chunkSize = this.chunkSize || 10; var index = 0; this.responseText = ""; do { this.readyStateChange(FakeXDomainRequest.LOADING); this.responseText += body.substring(index, index + chunkSize); index += chunkSize; } while (index < body.length); this.readyStateChange(FakeXDomainRequest.DONE); }, respond: function respond(status, contentType, body) { // content-type ignored, since XDomainRequest does not carry this // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease // test integration across browsers this.status = typeof status === "number" ? status : 200; this.setResponseBody(body || ""); }, simulatetimeout: function simulatetimeout() { this.status = 0; this.isTimeout = true; // Access to this should actually throw an error this.responseText = undefined; this.readyStateChange(FakeXDomainRequest.DONE); } }); sinon.extend(FakeXDomainRequest, { UNSENT: 0, OPENED: 1, LOADING: 3, DONE: 4 }); sinon.useFakeXDomainRequest = function useFakeXDomainRequest() { sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) { if (xdr.supportsXDR) { global.XDomainRequest = xdr.GlobalXDomainRequest; } delete sinon.FakeXDomainRequest.restore; if (keepOnCreate !== true) { delete sinon.FakeXDomainRequest.onCreate; } }; if (xdr.supportsXDR) { global.XDomainRequest = sinon.FakeXDomainRequest; } return sinon.FakeXDomainRequest; }; sinon.FakeXDomainRequest = FakeXDomainRequest; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./core"); require("../extend"); require("./event"); require("../log_error"); makeApi(sinon); module.exports = sinon; } if (isAMD) { define(loadDependencies); } else if (isNode) { loadDependencies(require, module.exports, module); } else { makeApi(sinon); // eslint-disable-line no-undef } })(typeof global !== "undefined" ? global : self); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/util/fake_xml_http_request.js000066400000000000000000000615511276775511300277250ustar00rootroot00000000000000/** * @depend core.js * @depend ../extend.js * @depend event.js * @depend ../log_error.js */ /** * Fake XMLHttpRequest object * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ (function (sinonGlobal, global) { "use strict"; function getWorkingXHR(globalScope) { var supportsXHR = typeof globalScope.XMLHttpRequest !== "undefined"; if (supportsXHR) { return globalScope.XMLHttpRequest; } var supportsActiveX = typeof globalScope.ActiveXObject !== "undefined"; if (supportsActiveX) { return function () { return new globalScope.ActiveXObject("MSXML2.XMLHTTP.3.0"); }; } return false; } var supportsProgress = typeof ProgressEvent !== "undefined"; var supportsCustomEvent = typeof CustomEvent !== "undefined"; var supportsFormData = typeof FormData !== "undefined"; var supportsArrayBuffer = typeof ArrayBuffer !== "undefined"; var supportsBlob = (function () { try { return !!new Blob(); } catch (e) { return false; } })(); var sinonXhr = { XMLHttpRequest: global.XMLHttpRequest }; sinonXhr.GlobalXMLHttpRequest = global.XMLHttpRequest; sinonXhr.GlobalActiveXObject = global.ActiveXObject; sinonXhr.supportsActiveX = typeof sinonXhr.GlobalActiveXObject !== "undefined"; sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest !== "undefined"; sinonXhr.workingXHR = getWorkingXHR(global); sinonXhr.supportsCORS = sinonXhr.supportsXHR && "withCredentials" in (new sinonXhr.GlobalXMLHttpRequest()); var unsafeHeaders = { "Accept-Charset": true, "Accept-Encoding": true, Connection: true, "Content-Length": true, Cookie: true, Cookie2: true, "Content-Transfer-Encoding": true, Date: true, Expect: true, Host: true, "Keep-Alive": true, Referer: true, TE: true, Trailer: true, "Transfer-Encoding": true, Upgrade: true, "User-Agent": true, Via: true }; // An upload object is created for each // FakeXMLHttpRequest and allows upload // events to be simulated using uploadProgress // and uploadError. function UploadProgress() { this.eventListeners = { abort: [], error: [], load: [], loadend: [], progress: [] }; } UploadProgress.prototype.addEventListener = function addEventListener(event, listener) { this.eventListeners[event].push(listener); }; UploadProgress.prototype.removeEventListener = function removeEventListener(event, listener) { var listeners = this.eventListeners[event] || []; for (var i = 0, l = listeners.length; i < l; ++i) { if (listeners[i] === listener) { return listeners.splice(i, 1); } } }; UploadProgress.prototype.dispatchEvent = function dispatchEvent(event) { var listeners = this.eventListeners[event.type] || []; for (var i = 0, listener; (listener = listeners[i]) != null; i++) { listener(event); } }; // Note that for FakeXMLHttpRequest to work pre ES5 // we lose some of the alignment with the spec. // To ensure as close a match as possible, // set responseType before calling open, send or respond; function FakeXMLHttpRequest() { this.readyState = FakeXMLHttpRequest.UNSENT; this.requestHeaders = {}; this.requestBody = null; this.status = 0; this.statusText = ""; this.upload = new UploadProgress(); this.responseType = ""; this.response = ""; if (sinonXhr.supportsCORS) { this.withCredentials = false; } var xhr = this; var events = ["loadstart", "load", "abort", "error", "loadend"]; function addEventListener(eventName) { xhr.addEventListener(eventName, function (event) { var listener = xhr["on" + eventName]; if (listener && typeof listener === "function") { listener.call(this, event); } }); } for (var i = events.length - 1; i >= 0; i--) { addEventListener(events[i]); } if (typeof FakeXMLHttpRequest.onCreate === "function") { FakeXMLHttpRequest.onCreate(this); } } function verifyState(xhr) { if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { throw new Error("INVALID_STATE_ERR"); } if (xhr.sendFlag) { throw new Error("INVALID_STATE_ERR"); } } function getHeader(headers, header) { header = header.toLowerCase(); for (var h in headers) { if (h.toLowerCase() === header) { return h; } } return null; } // filtering to enable a white-list version of Sinon FakeXhr, // where whitelisted requests are passed through to real XHR function each(collection, callback) { if (!collection) { return; } for (var i = 0, l = collection.length; i < l; i += 1) { callback(collection[i]); } } function some(collection, callback) { for (var index = 0; index < collection.length; index++) { if (callback(collection[index]) === true) { return true; } } return false; } // largest arity in XHR is 5 - XHR#open var apply = function (obj, method, args) { switch (args.length) { case 0: return obj[method](); case 1: return obj[method](args[0]); case 2: return obj[method](args[0], args[1]); case 3: return obj[method](args[0], args[1], args[2]); case 4: return obj[method](args[0], args[1], args[2], args[3]); case 5: return obj[method](args[0], args[1], args[2], args[3], args[4]); } }; FakeXMLHttpRequest.filters = []; FakeXMLHttpRequest.addFilter = function addFilter(fn) { this.filters.push(fn); }; var IE6Re = /MSIE 6/; FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) { var xhr = new sinonXhr.workingXHR(); // eslint-disable-line new-cap each([ "open", "setRequestHeader", "send", "abort", "getResponseHeader", "getAllResponseHeaders", "addEventListener", "overrideMimeType", "removeEventListener" ], function (method) { fakeXhr[method] = function () { return apply(xhr, method, arguments); }; }); var copyAttrs = function (args) { each(args, function (attr) { try { fakeXhr[attr] = xhr[attr]; } catch (e) { if (!IE6Re.test(navigator.userAgent)) { throw e; } } }); }; var stateChange = function stateChange() { fakeXhr.readyState = xhr.readyState; if (xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) { copyAttrs(["status", "statusText"]); } if (xhr.readyState >= FakeXMLHttpRequest.LOADING) { copyAttrs(["responseText", "response"]); } if (xhr.readyState === FakeXMLHttpRequest.DONE) { copyAttrs(["responseXML"]); } if (fakeXhr.onreadystatechange) { fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr }); } }; if (xhr.addEventListener) { for (var event in fakeXhr.eventListeners) { if (fakeXhr.eventListeners.hasOwnProperty(event)) { /*eslint-disable no-loop-func*/ each(fakeXhr.eventListeners[event], function (handler) { xhr.addEventListener(event, handler); }); /*eslint-enable no-loop-func*/ } } xhr.addEventListener("readystatechange", stateChange); } else { xhr.onreadystatechange = stateChange; } apply(xhr, "open", xhrArgs); }; FakeXMLHttpRequest.useFilters = false; function verifyRequestOpened(xhr) { if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { throw new Error("INVALID_STATE_ERR - " + xhr.readyState); } } function verifyRequestSent(xhr) { if (xhr.readyState === FakeXMLHttpRequest.DONE) { throw new Error("Request done"); } } function verifyHeadersReceived(xhr) { if (xhr.async && xhr.readyState !== FakeXMLHttpRequest.HEADERS_RECEIVED) { throw new Error("No headers received"); } } function verifyResponseBodyType(body) { if (typeof body !== "string") { var error = new Error("Attempted to respond to fake XMLHttpRequest with " + body + ", which is not a string."); error.name = "InvalidBodyException"; throw error; } } function convertToArrayBuffer(body) { var buffer = new ArrayBuffer(body.length); var view = new Uint8Array(buffer); for (var i = 0; i < body.length; i++) { var charCode = body.charCodeAt(i); if (charCode >= 256) { throw new TypeError("arraybuffer or blob responseTypes require binary string, " + "invalid character " + body[i] + " found."); } view[i] = charCode; } return buffer; } function isXmlContentType(contentType) { return !contentType || /(text\/xml)|(application\/xml)|(\+xml)/.test(contentType); } function convertResponseBody(responseType, contentType, body) { if (responseType === "" || responseType === "text") { return body; } else if (supportsArrayBuffer && responseType === "arraybuffer") { return convertToArrayBuffer(body); } else if (responseType === "json") { try { return JSON.parse(body); } catch (e) { // Return parsing failure as null return null; } } else if (supportsBlob && responseType === "blob") { var blobOptions = {}; if (contentType) { blobOptions.type = contentType; } return new Blob([convertToArrayBuffer(body)], blobOptions); } else if (responseType === "document") { if (isXmlContentType(contentType)) { return FakeXMLHttpRequest.parseXML(body); } return null; } throw new Error("Invalid responseType " + responseType); } function clearResponse(xhr) { if (xhr.responseType === "" || xhr.responseType === "text") { xhr.response = xhr.responseText = ""; } else { xhr.response = xhr.responseText = null; } xhr.responseXML = null; } FakeXMLHttpRequest.parseXML = function parseXML(text) { // Treat empty string as parsing failure if (text !== "") { try { if (typeof DOMParser !== "undefined") { var parser = new DOMParser(); return parser.parseFromString(text, "text/xml"); } var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = "false"; xmlDoc.loadXML(text); return xmlDoc; } catch (e) { // Unable to parse XML - no biggie } } return null; }; FakeXMLHttpRequest.statusCodes = { 100: "Continue", 101: "Switching Protocols", 200: "OK", 201: "Created", 202: "Accepted", 203: "Non-Authoritative Information", 204: "No Content", 205: "Reset Content", 206: "Partial Content", 207: "Multi-Status", 300: "Multiple Choice", 301: "Moved Permanently", 302: "Found", 303: "See Other", 304: "Not Modified", 305: "Use Proxy", 307: "Temporary Redirect", 400: "Bad Request", 401: "Unauthorized", 402: "Payment Required", 403: "Forbidden", 404: "Not Found", 405: "Method Not Allowed", 406: "Not Acceptable", 407: "Proxy Authentication Required", 408: "Request Timeout", 409: "Conflict", 410: "Gone", 411: "Length Required", 412: "Precondition Failed", 413: "Request Entity Too Large", 414: "Request-URI Too Long", 415: "Unsupported Media Type", 416: "Requested Range Not Satisfiable", 417: "Expectation Failed", 422: "Unprocessable Entity", 500: "Internal Server Error", 501: "Not Implemented", 502: "Bad Gateway", 503: "Service Unavailable", 504: "Gateway Timeout", 505: "HTTP Version Not Supported" }; function makeApi(sinon) { sinon.xhr = sinonXhr; sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, { async: true, open: function open(method, url, async, username, password) { this.method = method; this.url = url; this.async = typeof async === "boolean" ? async : true; this.username = username; this.password = password; clearResponse(this); this.requestHeaders = {}; this.sendFlag = false; if (FakeXMLHttpRequest.useFilters === true) { var xhrArgs = arguments; var defake = some(FakeXMLHttpRequest.filters, function (filter) { return filter.apply(this, xhrArgs); }); if (defake) { return FakeXMLHttpRequest.defake(this, arguments); } } this.readyStateChange(FakeXMLHttpRequest.OPENED); }, readyStateChange: function readyStateChange(state) { this.readyState = state; var readyStateChangeEvent = new sinon.Event("readystatechange", false, false, this); var event, progress; if (typeof this.onreadystatechange === "function") { try { this.onreadystatechange(readyStateChangeEvent); } catch (e) { sinon.logError("Fake XHR onreadystatechange handler", e); } } if (this.readyState === FakeXMLHttpRequest.DONE) { // ensure loaded and total are numbers progress = { loaded: this.progress || 0, total: this.progress || 0 }; if (this.status === 0) { event = this.aborted ? "abort" : "error"; } else { event = "load"; } if (supportsProgress) { this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progress, this)); this.upload.dispatchEvent(new sinon.ProgressEvent(event, progress, this)); this.upload.dispatchEvent(new sinon.ProgressEvent("loadend", progress, this)); } this.dispatchEvent(new sinon.ProgressEvent("progress", progress, this)); this.dispatchEvent(new sinon.ProgressEvent(event, progress, this)); this.dispatchEvent(new sinon.ProgressEvent("loadend", progress, this)); } this.dispatchEvent(readyStateChangeEvent); }, setRequestHeader: function setRequestHeader(header, value) { verifyState(this); if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) { throw new Error("Refused to set unsafe header \"" + header + "\""); } if (this.requestHeaders[header]) { this.requestHeaders[header] += "," + value; } else { this.requestHeaders[header] = value; } }, // Helps testing setResponseHeaders: function setResponseHeaders(headers) { verifyRequestOpened(this); this.responseHeaders = {}; for (var header in headers) { if (headers.hasOwnProperty(header)) { this.responseHeaders[header] = headers[header]; } } if (this.async) { this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED); } else { this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED; } }, // Currently treats ALL data as a DOMString (i.e. no Document) send: function send(data) { verifyState(this); if (!/^(get|head)$/i.test(this.method)) { var contentType = getHeader(this.requestHeaders, "Content-Type"); if (this.requestHeaders[contentType]) { var value = this.requestHeaders[contentType].split(";"); this.requestHeaders[contentType] = value[0] + ";charset=utf-8"; } else if (supportsFormData && !(data instanceof FormData)) { this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; } this.requestBody = data; } this.errorFlag = false; this.sendFlag = this.async; clearResponse(this); this.readyStateChange(FakeXMLHttpRequest.OPENED); if (typeof this.onSend === "function") { this.onSend(this); } this.dispatchEvent(new sinon.Event("loadstart", false, false, this)); }, abort: function abort() { this.aborted = true; clearResponse(this); this.errorFlag = true; this.requestHeaders = {}; this.responseHeaders = {}; if (this.readyState > FakeXMLHttpRequest.UNSENT && this.sendFlag) { this.readyStateChange(FakeXMLHttpRequest.DONE); this.sendFlag = false; } this.readyState = FakeXMLHttpRequest.UNSENT; }, error: function error() { clearResponse(this); this.errorFlag = true; this.requestHeaders = {}; this.responseHeaders = {}; this.readyStateChange(FakeXMLHttpRequest.DONE); }, getResponseHeader: function getResponseHeader(header) { if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { return null; } if (/^Set-Cookie2?$/i.test(header)) { return null; } header = getHeader(this.responseHeaders, header); return this.responseHeaders[header] || null; }, getAllResponseHeaders: function getAllResponseHeaders() { if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { return ""; } var headers = ""; for (var header in this.responseHeaders) { if (this.responseHeaders.hasOwnProperty(header) && !/^Set-Cookie2?$/i.test(header)) { headers += header + ": " + this.responseHeaders[header] + "\r\n"; } } return headers; }, setResponseBody: function setResponseBody(body) { verifyRequestSent(this); verifyHeadersReceived(this); verifyResponseBodyType(body); var contentType = this.getResponseHeader("Content-Type"); var isTextResponse = this.responseType === "" || this.responseType === "text"; clearResponse(this); if (this.async) { var chunkSize = this.chunkSize || 10; var index = 0; do { this.readyStateChange(FakeXMLHttpRequest.LOADING); if (isTextResponse) { this.responseText = this.response += body.substring(index, index + chunkSize); } index += chunkSize; } while (index < body.length); } this.response = convertResponseBody(this.responseType, contentType, body); if (isTextResponse) { this.responseText = this.response; } if (this.responseType === "document") { this.responseXML = this.response; } else if (this.responseType === "" && isXmlContentType(contentType)) { this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); } this.progress = body.length; this.readyStateChange(FakeXMLHttpRequest.DONE); }, respond: function respond(status, headers, body) { this.status = typeof status === "number" ? status : 200; this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; this.setResponseHeaders(headers || {}); this.setResponseBody(body || ""); }, uploadProgress: function uploadProgress(progressEventRaw) { if (supportsProgress) { this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); } }, downloadProgress: function downloadProgress(progressEventRaw) { if (supportsProgress) { this.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); } }, uploadError: function uploadError(error) { if (supportsCustomEvent) { this.upload.dispatchEvent(new sinon.CustomEvent("error", {detail: error})); } } }); sinon.extend(FakeXMLHttpRequest, { UNSENT: 0, OPENED: 1, HEADERS_RECEIVED: 2, LOADING: 3, DONE: 4 }); sinon.useFakeXMLHttpRequest = function () { FakeXMLHttpRequest.restore = function restore(keepOnCreate) { if (sinonXhr.supportsXHR) { global.XMLHttpRequest = sinonXhr.GlobalXMLHttpRequest; } if (sinonXhr.supportsActiveX) { global.ActiveXObject = sinonXhr.GlobalActiveXObject; } delete FakeXMLHttpRequest.restore; if (keepOnCreate !== true) { delete FakeXMLHttpRequest.onCreate; } }; if (sinonXhr.supportsXHR) { global.XMLHttpRequest = FakeXMLHttpRequest; } if (sinonXhr.supportsActiveX) { global.ActiveXObject = function ActiveXObject(objId) { if (objId === "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { return new FakeXMLHttpRequest(); } return new sinonXhr.GlobalActiveXObject(objId); }; } return FakeXMLHttpRequest; }; sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; function loadDependencies(require, exports, module) { var sinon = require("./core"); require("../extend"); require("./event"); require("../log_error"); makeApi(sinon); module.exports = sinon; } if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon, // eslint-disable-line no-undef typeof global !== "undefined" ? global : self )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/util/timers_ie.js000066400000000000000000000024141276775511300253010ustar00rootroot00000000000000/** * Helps IE run the fake timers. By defining global functions, IE allows * them to be overwritten at a later point. If these are not defined like * this, overwriting them will result in anything from an exception to browser * crash. * * If you don't require fake timers to work in IE, don't include this file. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ /*eslint-disable strict, no-inner-declarations, no-unused-vars*/ if (typeof window !== "undefined") { function setTimeout() {} function clearTimeout() {} function setImmediate() {} function clearImmediate() {} function setInterval() {} function clearInterval() {} function Date() {} // Reassign the original functions. Now their writable attribute // should be true. Hackish, I know, but it works. /*global sinon*/ setTimeout = sinon.timers.setTimeout; clearTimeout = sinon.timers.clearTimeout; setImmediate = sinon.timers.setImmediate; clearImmediate = sinon.timers.clearImmediate; setInterval = sinon.timers.setInterval; clearInterval = sinon.timers.clearInterval; Date = sinon.timers.Date; // eslint-disable-line no-native-reassign } /*eslint-enable no-inner-declarations*/ sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/util/xdr_ie.js000066400000000000000000000013121276775511300245670ustar00rootroot00000000000000/** * Helps IE run the fake XDomainRequest. By defining global functions, IE allows * them to be overwritten at a later point. If these are not defined like * this, overwriting them will result in anything from an exception to browser * crash. * * If you don't require fake XDR to work in IE, don't include this file. */ /*eslint-disable strict*/ if (typeof window !== "undefined") { function XDomainRequest() {} // eslint-disable-line no-unused-vars, no-inner-declarations // Reassign the original function. Now its writable attribute // should be true. Hackish, I know, but it works. /*global sinon*/ XDomainRequest = sinon.xdr.XDomainRequest || undefined; } /*eslint-enable strict*/ sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/util/xhr_ie.js000066400000000000000000000015051276775511300245770ustar00rootroot00000000000000/** * Helps IE run the fake XMLHttpRequest. By defining global functions, IE allows * them to be overwritten at a later point. If these are not defined like * this, overwriting them will result in anything from an exception to browser * crash. * * If you don't require fake XHR to work in IE, don't include this file. * * @author Christian Johansen (christian@cjohansen.no) * @license BSD * * Copyright (c) 2010-2013 Christian Johansen */ /*eslint-disable strict*/ if (typeof window !== "undefined") { function XMLHttpRequest() {} // eslint-disable-line no-unused-vars, no-inner-declarations // Reassign the original function. Now its writable attribute // should be true. Hackish, I know, but it works. /*global sinon*/ XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined; } /*eslint-enable strict*/ sinon-4eaad42f0715face6b53899fad7bcbc49d079417/lib/sinon/walk.js000066400000000000000000000054261276775511300233100ustar00rootroot00000000000000/** * @depend util/core.js */ (function (sinonGlobal) { "use strict"; function makeApi(sinon) { function walkInternal(obj, iterator, context, originalObj, seen) { var proto, prop; if (typeof Object.getOwnPropertyNames !== "function") { // We explicitly want to enumerate through all of the prototype's properties // in this case, therefore we deliberately leave out an own property check. /* eslint-disable guard-for-in */ for (prop in obj) { iterator.call(context, obj[prop], prop, obj); } /* eslint-enable guard-for-in */ return; } Object.getOwnPropertyNames(obj).forEach(function (k) { if (!seen[k]) { seen[k] = true; var target = typeof Object.getOwnPropertyDescriptor(obj, k).get === "function" ? originalObj : obj; iterator.call(context, target[k], k, target); } }); proto = Object.getPrototypeOf(obj); if (proto) { walkInternal(proto, iterator, context, originalObj, seen); } } /* Public: walks the prototype chain of an object and iterates over every own property * name encountered. The iterator is called in the same fashion that Array.prototype.forEach * works, where it is passed the value, key, and own object as the 1st, 2nd, and 3rd positional * argument, respectively. In cases where Object.getOwnPropertyNames is not available, walk will * default to using a simple for..in loop. * * obj - The object to walk the prototype chain for. * iterator - The function to be called on each pass of the walk. * context - (Optional) When given, the iterator will be called with this object as the receiver. */ function walk(obj, iterator, context) { return walkInternal(obj, iterator, context, obj, {}); } sinon.walk = walk; return sinon.walk; } function loadDependencies(require, exports, module) { var sinon = require("./util/core"); module.exports = makeApi(sinon); } var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; if (isAMD) { define(loadDependencies); return; } if (isNode) { loadDependencies(require, module.exports, module); return; } if (sinonGlobal) { makeApi(sinonGlobal); } }( typeof sinon === "object" && sinon // eslint-disable-line no-undef )); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/package.json000066400000000000000000000026061276775511300224030ustar00rootroot00000000000000{ "name": "sinon", "description": "JavaScript test spies, stubs and mocks.", "version": "1.17.5", "homepage": "http://sinonjs.org/", "author": "Christian Johansen", "repository": { "type": "git", "url": "http://github.com/cjohansen/Sinon.JS.git" }, "bugs": { "mail": "christian@cjohansen.no", "url": "http://github.com/cjohansen/Sinon.JS/issues" }, "license": "BSD-3-Clause", "scripts": { "build": "./build", "check-clean-wd": "./scripts/is-clean-wd.sh", "clean": "rimraf pkg", "ci-test": "npm run lint && ./scripts/ci-test.sh", "test": "./scripts/ci-test.sh", "lint": "eslint .", "prepublish": "npm-run-all check-clean-wd clean build", "eslint-pre-commit": "./scripts/eslint-pre-commit" }, "pre-commit": [ "eslint-pre-commit" ], "dependencies": { "formatio": "1.1.1", "util": ">=0.10.3 <1", "lolex": "1.3.2", "samsam": "1.1.2" }, "devDependencies": { "buster": "0.7.18", "buster-core": "^0.6.4", "buster-istanbul": "0.1.13", "eslint": "0.24.0", "eslint-config-defaults": "^2.1.0", "jscs": "1.13.1", "npm-run-all": "^2.3.0", "pre-commit": "1.0.10", "rimraf": "^2.5.4" }, "files": [ "lib", "pkg", "AUTHORS", "CONTRIBUTING.md", "Changelog.txt", "LICENSE", "README.md" ], "main": "./lib/sinon.js", "engines": { "node": ">=0.1.103" } } sinon-4eaad42f0715face6b53899fad7bcbc49d079417/release.sh000077500000000000000000000006661276775511300221000ustar00rootroot00000000000000git push git push --tags npm publish rm -f pkg/* ruby -rubygems build cp pkg/* ../sinon-web/releases/. cp Changelog.txt ../sinon-web/. cd ../sinon-web sed -i "s/2013\-[0-9][0-9]\-[0-9][0-9] \-/`date +%Y`-`date +%m`-`date +%d` -/" index.html sed -i "s/2013\-[0-9][0-9]\-[0-9][0-9] \-/`date +%Y`-`date +%m`-`date +%d` -/" qunit/index.html sed -i "s/$1/$2/g" index.html sed -i "s/$1/$2/g" qunit/index.html sed -i "s/$1/$2/g" docs/index.html sinon-4eaad42f0715face6b53899fad7bcbc49d079417/scripts/000077500000000000000000000000001276775511300216005ustar00rootroot00000000000000sinon-4eaad42f0715face6b53899fad7bcbc49d079417/scripts/ci-test.sh000077500000000000000000000014001276775511300235020ustar00rootroot00000000000000#!/bin/bash set -eu function finish { if [ -n "${TRAVIS+1}" ]; then echo "TRAVIS detected, skip killing child processes" else kill $(jobs -pr) fi } trap finish SIGINT SIGTERM EXIT echo echo starting buster-server ./node_modules/buster/bin/buster-server & # fork to a subshell sleep 4 # takes a while for buster server to start echo echo starting phantomjs phantomjs ./node_modules/buster/script/phantom.js & sleep 1 # give phantomjs a second to warm up echo echo "starting buster-test (source)" ./node_modules/buster/bin/buster-test --config-group coverage ./node_modules/buster/bin/buster-test --config-group node echo echo "starting buster-test (packaged)" ./build ./node_modules/buster/bin/buster-test --config test/buster-packaged.js sinon-4eaad42f0715face6b53899fad7bcbc49d079417/scripts/eslint-pre-commit000077500000000000000000000003471276775511300251020ustar00rootroot00000000000000#!/bin/bash git stash -q --keep-index # Test prospective commit git diff-index --cached HEAD --name-only --diff-filter ACMR | egrep '.js$' | xargs $(npm bin)/eslint RESULT=$? git stash pop -q [ $RESULT -ne 0 ] && exit 1 exit 0 sinon-4eaad42f0715face6b53899fad7bcbc49d079417/scripts/is-clean-wd.sh000077500000000000000000000003651276775511300242460ustar00rootroot00000000000000#!/bin/sh OUTPUT=$(git status --porcelain) if [[ "$OUTPUT" ]]; then echo "The index and/or working directory is unclean. Commit, delete or stash any uncommitted changes before continuing the release process." echo $OUTPUT exit 1 fi sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/000077500000000000000000000000001276775511300210705ustar00rootroot00000000000000sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/assert-test.js000066400000000000000000001536661276775511300237250ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; var refute = buster.refute; buster.testCase("sinon.assert", { setUp: function () { this.global = typeof window !== "undefined" ? window : global; this.setUpStubs = function () { this.stub = sinon.stub.create(); sinon.stub(sinon.assert, "fail").throws(); sinon.stub(sinon.assert, "pass"); }; this.tearDownStubs = function () { sinon.assert.fail.restore(); sinon.assert.pass.restore(); }; }, "is object": function () { assert.isObject(sinon.assert); }, "supports proxy property": function () { var failed = false; var api = { method: function () {} }; api.method.proxy = function () {}; sinon.spy(api, "method"); api.method(); try { sinon.assert.calledOnce(api.method); } catch (e) { failed = true; } assert.isFalse(failed); }, ".fail": { setUp: function () { this.exceptionName = sinon.assert.failException; }, tearDown: function () { sinon.assert.failException = this.exceptionName; }, "throws exception": function () { var failed = false; var exception; try { sinon.assert.fail("Some message"); failed = true; } catch (e) { exception = e; } assert.isFalse(failed); assert.equals(exception.name, "AssertError"); }, "throws configured exception type": function () { sinon.assert.failException = "RetardError"; assert.exception(function () { sinon.assert.fail("Some message"); }, "RetardError"); } }, ".match": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when arguments to not match": function () { assert.exception(function () { sinon.assert.match("foo", "bar"); }); assert(sinon.assert.fail.calledOnce); }, "passes when argumens match": function () { sinon.assert.match("foo", "foo"); assert(sinon.assert.pass.calledOnce); } }, ".called": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when method does not exist": function () { assert.exception(function () { sinon.assert.called(); }); assert(sinon.assert.fail.called); }, "fails when method is not stub": function () { assert.exception(function () { sinon.assert.called(function () {}); }); assert(sinon.assert.fail.called); }, "fails when method was not called": function () { var stub = this.stub; assert.exception(function () { sinon.assert.called(stub); }); assert(sinon.assert.fail.called); }, "fails when called with more than one argument": function () { var stub = this.stub; stub(); assert.exception(function () { sinon.assert.called(stub, 1); }); }, "does not fail when method was called": function () { var stub = this.stub; stub(); refute.exception(function () { sinon.assert.called(stub); }); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { var stub = this.stub; stub(); refute.exception(function () { sinon.assert.called(stub); }); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("called")); } }, ".notCalled": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when method does not exist": function () { assert.exception(function () { sinon.assert.notCalled(); }); assert(sinon.assert.fail.called); }, "fails when method is not stub": function () { assert.exception(function () { sinon.assert.notCalled(function () {}); }); assert(sinon.assert.fail.called); }, "fails when method was called": function () { var stub = this.stub; stub(); assert.exception(function () { sinon.assert.notCalled(stub); }); assert(sinon.assert.fail.called); }, "fails when called with more than one argument": function () { var stub = this.stub; assert.exception(function () { sinon.assert.notCalled(stub, 1); }); }, "passes when method was not called": function () { var stub = this.stub; refute.exception(function () { sinon.assert.notCalled(stub); }); assert.isFalse(sinon.assert.fail.called); }, "should call pass callback": function () { var stub = this.stub; sinon.assert.notCalled(stub); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("notCalled")); } }, ".calledOnce": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when method does not exist": function () { assert.exception(function () { sinon.assert.calledOnce(); }); assert(sinon.assert.fail.called); }, "fails when method is not stub": function () { assert.exception(function () { sinon.assert.calledOnce(function () {}); }); assert(sinon.assert.fail.called); }, "fails when called with more than one argument": function () { var stub = this.stub; stub(); assert.exception(function () { sinon.assert.calledOnce(stub, 1); }); }, "fails when method was not called": function () { var stub = this.stub; assert.exception(function () { sinon.assert.calledOnce(stub); }); assert(sinon.assert.fail.called); }, "passes when method was called": function () { var stub = this.stub; stub(); refute.exception(function () { sinon.assert.calledOnce(stub); }); assert.isFalse(sinon.assert.fail.called); }, "fails when method was called more than once": function () { var stub = this.stub; stub(); stub(); assert.exception(function () { sinon.assert.calledOnce(stub); }); assert(sinon.assert.fail.called); }, "calls pass callback": function () { var stub = this.stub; stub(); sinon.assert.calledOnce(stub); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("calledOnce")); } }, ".calledTwice": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails if called once": function () { var stub = this.stub; this.stub(); assert.exception(function () { sinon.assert.calledTwice(stub); }); }, "fails when called with more than one argument": function () { var stub = this.stub; this.stub(); this.stub(); assert.exception(function () { sinon.assert.calledTwice(stub, 1); }); }, "passes if called twice": function () { var stub = this.stub; this.stub(); this.stub(); refute.exception(function () { sinon.assert.calledTwice(stub); }); }, "calls pass callback": function () { var stub = this.stub; stub(); stub(); sinon.assert.calledTwice(stub); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("calledTwice")); } }, ".calledThrice": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails if called once": function () { var stub = this.stub; this.stub(); assert.exception(function () { sinon.assert.calledThrice(stub); }); }, "fails when called with more than one argument": function () { var stub = this.stub; this.stub(); this.stub(); this.stub(); assert.exception(function () { sinon.assert.calledThrice(stub, 1); }); }, "passes if called thrice": function () { var stub = this.stub; this.stub(); this.stub(); this.stub(); refute.exception(function () { sinon.assert.calledThrice(stub); }); }, "calls pass callback": function () { var stub = this.stub; stub(); stub(); stub(); sinon.assert.calledThrice(stub); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("calledThrice")); } }, ".callOrder": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "passes when calls where done in right order": function () { var spy1 = sinon.spy(); var spy2 = sinon.spy(); spy1(); spy2(); refute.exception(function () { sinon.assert.callOrder(spy1, spy2); }); }, "fails when calls where done in wrong order": function () { var spy1 = sinon.spy(); var spy2 = sinon.spy(); spy2(); spy1(); assert.exception(function () { sinon.assert.callOrder(spy1, spy2); }); assert(sinon.assert.fail.called); }, "passes when many calls where done in right order": function () { var spy1 = sinon.spy(); var spy2 = sinon.spy(); var spy3 = sinon.spy(); var spy4 = sinon.spy(); spy1(); spy2(); spy3(); spy4(); refute.exception(function () { sinon.assert.callOrder(spy1, spy2, spy3, spy4); }); }, "fails when one of many calls where done in wrong order": function () { var spy1 = sinon.spy(); var spy2 = sinon.spy(); var spy3 = sinon.spy(); var spy4 = sinon.spy(); spy1(); spy2(); spy4(); spy3(); assert.exception(function () { sinon.assert.callOrder(spy1, spy2, spy3, spy4); }); assert(sinon.assert.fail.called); }, "calls pass callback": function () { var stubs = [sinon.spy(), sinon.spy()]; stubs[0](); stubs[1](); sinon.assert.callOrder(stubs[0], stubs[1]); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("callOrder")); }, "passes for multiple calls to same spy": function () { var first = sinon.spy(); var second = sinon.spy(); first(); second(); first(); refute.exception(function () { sinon.assert.callOrder(first, second, first); }); }, "fails if first spy was not called": function () { var first = sinon.spy(); var second = sinon.spy(); second(); assert.exception(function () { sinon.assert.callOrder(first, second); }); }, "fails if second spy was not called": function () { var first = sinon.spy(); var second = sinon.spy(); first(); assert.exception(function () { sinon.assert.callOrder(first, second); }); } }, ".calledOn": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when method does not exist": function () { var object = {}; sinon.stub(this.stub, "calledOn"); assert.exception(function () { sinon.assert.calledOn(null, object); }); assert.isFalse(this.stub.calledOn.calledWith(object)); assert(sinon.assert.fail.called); }, "fails when method is not stub": function () { var object = {}; sinon.stub(this.stub, "calledOn"); assert.exception(function () { sinon.assert.calledOn(function () {}, object); }); assert.isFalse(this.stub.calledOn.calledWith(object)); assert(sinon.assert.fail.called); }, "fails when method fails": function () { var object = {}; sinon.stub(this.stub, "calledOn").returns(false); var stub = this.stub; assert.exception(function () { sinon.assert.calledOn(stub, object); }); assert(sinon.assert.fail.called); }, "passes when method doesn't fail": function () { var object = {}; sinon.stub(this.stub, "calledOn").returns(true); var stub = this.stub; sinon.assert.calledOn(stub, object); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { var obj = {}; this.stub.call(obj); sinon.assert.calledOn(this.stub, obj); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("calledOn")); } }, ".calledWithNew": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when method does not exist": function () { sinon.stub(this.stub, "calledWithNew"); assert.exception(function () { sinon.assert.calledWithNew(null); }); assert.isFalse(this.stub.calledWithNew.called); assert(sinon.assert.fail.called); }, "fails when method is not stub": function () { sinon.stub(this.stub, "calledWithNew"); assert.exception(function () { sinon.assert.calledWithNew(function () {}); }); assert.isFalse(this.stub.calledWithNew.called); assert(sinon.assert.fail.called); }, "fails when method fails": function () { sinon.stub(this.stub, "calledWithNew").returns(false); var stub = this.stub; assert.exception(function () { sinon.assert.calledWithNew(stub); }); assert(sinon.assert.fail.called); }, "passes when method doesn't fail": function () { sinon.stub(this.stub, "calledWithNew").returns(true); var stub = this.stub; sinon.assert.calledWithNew(stub); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { new this.stub(); // eslint-disable-line no-new, new-cap sinon.assert.calledWithNew(this.stub); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("calledWithNew")); } }, ".alwaysCalledWithNew": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when method does not exist": function () { sinon.stub(this.stub, "alwaysCalledWithNew"); assert.exception(function () { sinon.assert.alwaysCalledWithNew(null); }); assert.isFalse(this.stub.alwaysCalledWithNew.called); assert(sinon.assert.fail.called); }, "fails when method is not stub": function () { sinon.stub(this.stub, "alwaysCalledWithNew"); assert.exception(function () { sinon.assert.alwaysCalledWithNew(function () {}); }); assert.isFalse(this.stub.alwaysCalledWithNew.called); assert(sinon.assert.fail.called); }, "fails when method fails": function () { sinon.stub(this.stub, "alwaysCalledWithNew").returns(false); var stub = this.stub; assert.exception(function () { sinon.assert.alwaysCalledWithNew(stub); }); assert(sinon.assert.fail.called); }, "passes when method doesn't fail": function () { sinon.stub(this.stub, "alwaysCalledWithNew").returns(true); var stub = this.stub; sinon.assert.alwaysCalledWithNew(stub); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { new this.stub(); // eslint-disable-line no-new, new-cap sinon.assert.alwaysCalledWithNew(this.stub); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("alwaysCalledWithNew")); } }, ".calledWith": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when method fails": function () { var object = {}; sinon.stub(this.stub, "calledWith").returns(false); var stub = this.stub; assert.exception(function () { sinon.assert.calledWith(stub, object, 1); }); assert(this.stub.calledWith.calledWith(object, 1)); assert(sinon.assert.fail.called); }, "passes when method doesn't fail": function () { var object = {}; sinon.stub(this.stub, "calledWith").returns(true); var stub = this.stub; refute.exception(function () { sinon.assert.calledWith(stub, object, 1); }); assert(this.stub.calledWith.calledWith(object, 1)); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { this.stub("yeah"); sinon.assert.calledWith(this.stub, "yeah"); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("calledWith")); }, "works with spyCall": function () { var spy = sinon.spy(); var object = {}; spy(); spy(object); sinon.assert.calledWith(spy.lastCall, object); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("calledWith")); }, "fails when spyCall failed": function () { var spy = sinon.spy(); var object = {}; spy(); spy(object); assert.exception(function () { sinon.assert.calledWith(spy.lastCall, 1); }); assert(sinon.assert.fail.called); } }, ".calledWithExactly": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when method fails": function () { var object = {}; sinon.stub(this.stub, "calledWithExactly").returns(false); var stub = this.stub; assert.exception(function () { sinon.assert.calledWithExactly(stub, object, 1); }); assert(this.stub.calledWithExactly.calledWithExactly(object, 1)); assert(sinon.assert.fail.called); }, "passes when method doesn't fail": function () { var object = {}; sinon.stub(this.stub, "calledWithExactly").returns(true); var stub = this.stub; refute.exception(function () { sinon.assert.calledWithExactly(stub, object, 1); }); assert(this.stub.calledWithExactly.calledWithExactly(object, 1)); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { this.stub("yeah"); sinon.assert.calledWithExactly(this.stub, "yeah"); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("calledWithExactly")); } }, ".neverCalledWith": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when method fails": function () { var object = {}; sinon.stub(this.stub, "neverCalledWith").returns(false); var stub = this.stub; assert.exception(function () { sinon.assert.neverCalledWith(stub, object, 1); }); assert(this.stub.neverCalledWith.calledWith(object, 1)); assert(sinon.assert.fail.called); }, "passes when method doesn't fail": function () { var object = {}; sinon.stub(this.stub, "neverCalledWith").returns(true); var stub = this.stub; refute.exception(function () { sinon.assert.neverCalledWith(stub, object, 1); }); assert(this.stub.neverCalledWith.calledWith(object, 1)); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { this.stub("yeah"); sinon.assert.neverCalledWith(this.stub, "nah!"); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("neverCalledWith")); } }, ".threwTest": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when method fails": function () { sinon.stub(this.stub, "threw").returns(false); var stub = this.stub; assert.exception(function () { sinon.assert.threw(stub, 1, 2); }); assert(this.stub.threw.calledWithExactly(1, 2)); assert(sinon.assert.fail.called); }, "passes when method doesn't fail": function () { sinon.stub(this.stub, "threw").returns(true); var stub = this.stub; refute.exception(function () { sinon.assert.threw(stub, 1, 2); }); assert(this.stub.threw.calledWithExactly(1, 2)); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { sinon.stub(this.stub, "threw").returns(true); this.stub(); sinon.assert.threw(this.stub); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("threw")); } }, ".callCount": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails when method fails": function () { this.stub(); this.stub(); var stub = this.stub; assert.exception(function () { sinon.assert.callCount(stub, 3); }); assert(sinon.assert.fail.called); }, "passes when method doesn't fail": function () { var stub = this.stub; this.stub.callCount = 3; refute.exception(function () { sinon.assert.callCount(stub, 3); }); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { this.stub(); sinon.assert.callCount(this.stub, 1); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("callCount")); } }, ".alwaysCalledOn": { setUp: function () { this.setUpStubs(); }, tearDown: function () { this.tearDownStubs(); }, "fails if method is missing": function () { assert.exception(function () { sinon.assert.alwaysCalledOn(); }); }, "fails if method is not fake": function () { assert.exception(function () { sinon.assert.alwaysCalledOn(function () {}, {}); }); }, "fails if stub returns false": function () { var stub = sinon.stub(); sinon.stub(stub, "alwaysCalledOn").returns(false); assert.exception(function () { sinon.assert.alwaysCalledOn(stub, {}); }); assert(sinon.assert.fail.called); }, "passes if stub returns true": function () { var stub = sinon.stub.create(); sinon.stub(stub, "alwaysCalledOn").returns(true); sinon.assert.alwaysCalledOn(stub, {}); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { this.stub(); sinon.assert.alwaysCalledOn(this.stub, this); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("alwaysCalledOn")); } }, ".alwaysCalledWith": { setUp: function () { sinon.stub(sinon.assert, "fail").throws(); sinon.stub(sinon.assert, "pass"); }, tearDown: function () { sinon.assert.fail.restore(); sinon.assert.pass.restore(); }, "fails if method is missing": function () { assert.exception(function () { sinon.assert.alwaysCalledWith(); }); }, "fails if method is not fake": function () { assert.exception(function () { sinon.assert.alwaysCalledWith(function () {}); }); }, "fails if stub returns false": function () { var stub = sinon.stub.create(); sinon.stub(stub, "alwaysCalledWith").returns(false); assert.exception(function () { sinon.assert.alwaysCalledWith(stub, {}, []); }); assert(sinon.assert.fail.called); }, "passes if stub returns true": function () { var stub = sinon.stub.create(); sinon.stub(stub, "alwaysCalledWith").returns(true); sinon.assert.alwaysCalledWith(stub, {}, []); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { var spy = sinon.spy(); spy("Hello"); sinon.assert.alwaysCalledWith(spy, "Hello"); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("alwaysCalledWith")); } }, ".alwaysCalledWithExactly": { setUp: function () { sinon.stub(sinon.assert, "fail"); sinon.stub(sinon.assert, "pass"); }, tearDown: function () { sinon.assert.fail.restore(); sinon.assert.pass.restore(); }, "fails if stub returns false": function () { var stub = sinon.stub.create(); sinon.stub(stub, "alwaysCalledWithExactly").returns(false); sinon.assert.alwaysCalledWithExactly(stub, {}, []); assert(sinon.assert.fail.called); }, "passes if stub returns true": function () { var stub = sinon.stub.create(); sinon.stub(stub, "alwaysCalledWithExactly").returns(true); sinon.assert.alwaysCalledWithExactly(stub, {}, []); assert.isFalse(sinon.assert.fail.called); }, "calls pass callback": function () { var spy = sinon.spy(); spy("Hello"); sinon.assert.alwaysCalledWithExactly(spy, "Hello"); assert(sinon.assert.pass.calledOnce); assert(sinon.assert.pass.calledWith("alwaysCalledWithExactly")); } }, ".expose": { "exposes asserts into object": function () { var test = {}; sinon.assert.expose(test); assert.isFunction(test.fail); assert.isString(test.failException); assert.isFunction(test.assertCalled); assert.isFunction(test.assertCalledOn); assert.isFunction(test.assertCalledWith); assert.isFunction(test.assertCalledWithExactly); assert.isFunction(test.assertThrew); assert.isFunction(test.assertCallCount); }, "exposes asserts into global": function () { sinon.assert.expose(this.global, { includeFail: false }); assert.equals(typeof failException, "undefined"); /*eslint-disable no-undef*/ assert.isFunction(assertCalled); assert.isFunction(assertCalledOn); assert.isFunction(assertCalledWith); assert.isFunction(assertCalledWithExactly); assert.isFunction(assertThrew); assert.isFunction(assertCallCount); /*eslint-enable no-undef*/ }, "fails exposed asserts without errors": function () { sinon.assert.expose(this.global, { includeFail: false }); try { assertCalled(sinon.spy()); // eslint-disable-line no-undef } catch (e) { assert.equals(e.message, "expected spy to have been called at least once but was never called"); } }, "exposes asserts into object without prefixes": function () { var test = {}; sinon.assert.expose(test, { prefix: "" }); assert.isFunction(test.fail); assert.isString(test.failException); assert.isFunction(test.called); assert.isFunction(test.calledOn); assert.isFunction(test.calledWith); assert.isFunction(test.calledWithExactly); assert.isFunction(test.threw); assert.isFunction(test.callCount); }, "does not expose 'expose'": function () { var test = {}; sinon.assert.expose(test, { prefix: "" }); refute(test.expose, "Expose should not be exposed"); }, "throws if target is undefined": function () { assert.exception(function () { sinon.assert.expose(); }, "TypeError"); }, "throws if target is null": function () { assert.exception(function () { sinon.assert.expose(null); }, "TypeError"); } }, message: { setUp: function () { this.obj = { doSomething: function () {} }; sinon.spy(this.obj, "doSomething"); this.message = function (method) { try { sinon.assert[method].apply(sinon.assert, [].slice.call(arguments, 1)); } catch (e) { return e.message; } }; }, "assert.called exception message": function () { assert.equals(this.message("called", this.obj.doSomething), "expected doSomething to have been called at " + "least once but was never called"); }, "assert.notCalled exception message one call": function () { this.obj.doSomething(); assert.equals(this.message("notCalled", this.obj.doSomething).replace(/ at.*/g, ""), "expected doSomething to not have been called " + "but was called once\n doSomething()"); }, "assert.notCalled exception message four calls": function () { this.obj.doSomething(); this.obj.doSomething(); this.obj.doSomething(); this.obj.doSomething(); assert.equals(this.message("notCalled", this.obj.doSomething).replace(/ at.*/g, ""), "expected doSomething to not have been called " + "but was called 4 times\n doSomething()\n " + "doSomething()\n doSomething()\n doSomething()"); }, "assert.notCalled exception message with calls with arguments": function () { this.obj.doSomething(); this.obj.doSomething(3); this.obj.doSomething(42, 1); this.obj.doSomething(); assert.equals(this.message("notCalled", this.obj.doSomething).replace(/ at.*/g, ""), "expected doSomething to not have been called " + "but was called 4 times\n doSomething()\n " + "doSomething(3)\n doSomething(42, 1)\n doSomething()"); }, "assert.callOrder exception message": function () { var obj = { doop: function () {}, foo: function () {} }; sinon.spy(obj, "doop"); sinon.spy(obj, "foo"); obj.doop(); this.obj.doSomething(); obj.foo(); var message = this.message("callOrder", this.obj.doSomething, obj.doop, obj.foo); assert.equals(message, "expected doSomething, doop, foo to be called in " + "order but were called as doop, doSomething, foo"); }, "assert.callOrder with missing first call exception message": function () { var obj = { doop: function () {}, foo: function () {} }; sinon.spy(obj, "doop"); sinon.spy(obj, "foo"); obj.foo(); var message = this.message("callOrder", obj.doop, obj.foo); assert.equals(message, "expected doop, foo to be called in " + "order but were called as foo"); }, "assert.callOrder with missing last call exception message": function () { var obj = { doop: function () {}, foo: function () {} }; sinon.spy(obj, "doop"); sinon.spy(obj, "foo"); obj.doop(); var message = this.message("callOrder", obj.doop, obj.foo); assert.equals(message, "expected doop, foo to be called in " + "order but were called as doop"); }, "assert.callCount exception message": function () { this.obj.doSomething(); assert.equals(this.message("callCount", this.obj.doSomething, 3).replace(/ at.*/g, ""), "expected doSomething to be called thrice but was called " + "once\n doSomething()"); }, "assert.calledOnce exception message": function () { this.obj.doSomething(); this.obj.doSomething(); assert.equals(this.message("calledOnce", this.obj.doSomething).replace(/ at.*/g, ""), "expected doSomething to be called once but was called " + "twice\n doSomething()\n doSomething()"); this.obj.doSomething(); assert.equals(this.message("calledOnce", this.obj.doSomething).replace(/ at.*/g, ""), "expected doSomething to be called once but was called " + "thrice\n doSomething()\n doSomething()\n doSomething()"); }, "assert.calledTwice exception message": function () { this.obj.doSomething(); assert.equals(this.message("calledTwice", this.obj.doSomething).replace(/ at.*/g, ""), "expected doSomething to be called twice but was called " + "once\n doSomething()"); }, "assert.calledThrice exception message": function () { this.obj.doSomething(); this.obj.doSomething(); this.obj.doSomething(); this.obj.doSomething(); assert.equals( this.message("calledThrice", this.obj.doSomething).replace(/ at.*/g, ""), "expected doSomething to be called thrice but was called 4 times\n" + " doSomething()\n doSomething()\n doSomething()\n doSomething()" ); }, "assert.calledOn exception message": function () { this.obj.toString = function () { return "[Oh yeah]"; }; var obj = { toString: function () { return "[Oh no]"; } }; var obj2 = { toString: function () { return "[Oh well]"; } }; this.obj.doSomething.call(obj); this.obj.doSomething.call(obj2); assert.equals( this.message("calledOn", this.obj.doSomething, this.obj), "expected doSomething to be called with [Oh yeah] as this but was called with [Oh no], [Oh well]" ); }, "assert.alwaysCalledOn exception message": function () { this.obj.toString = function () { return "[Oh yeah]"; }; var obj = { toString: function () { return "[Oh no]"; } }; var obj2 = { toString: function () { return "[Oh well]"; } }; this.obj.doSomething.call(obj); this.obj.doSomething.call(obj2); this.obj.doSomething(); assert.equals( this.message("alwaysCalledOn", this.obj.doSomething, this.obj), "expected doSomething to always be called with [Oh yeah] as this but was called with " + "[Oh no], [Oh well], [Oh yeah]" ); }, "assert.calledWithNew exception message": function () { this.obj.doSomething(); assert.equals(this.message("calledWithNew", this.obj.doSomething), "expected doSomething to be called with new"); }, "assert.alwaysCalledWithNew exception message": function () { new this.obj.doSomething(); // eslint-disable-line no-new, new-cap this.obj.doSomething(); assert.equals(this.message("alwaysCalledWithNew", this.obj.doSomething), "expected doSomething to always be called with new"); }, "assert.calledWith exception message": function () { this.obj.doSomething(1, 3, "hey"); assert.equals(this.message("calledWith", this.obj.doSomething, 4, 3, "hey").replace(/ at.*/g, ""), "expected doSomething to be called with arguments 4, 3, " + "hey\n doSomething(1, 3, hey)"); }, "assert.calledWith match.any exception message": function () { this.obj.doSomething(true, true); assert.equals( this.message("calledWith", this.obj.doSomething, sinon.match.any, false).replace(/ at.*/g, ""), "expected doSomething to be called with arguments any, false\n doSomething(true, true)" ); }, "assert.calledWith match.defined exception message": function () { this.obj.doSomething(); assert.equals( this.message("calledWith", this.obj.doSomething, sinon.match.defined).replace(/ at.*/g, ""), "expected doSomething to be called with arguments defined\n doSomething()" ); }, "assert.calledWith match.truthy exception message": function () { this.obj.doSomething(); assert.equals( this.message("calledWith", this.obj.doSomething, sinon.match.truthy).replace(/ at.*/g, ""), "expected doSomething to be called with arguments truthy\n doSomething()" ); }, "assert.calledWith match.falsy exception message": function () { this.obj.doSomething(true); assert.equals(this.message("calledWith", this.obj.doSomething, sinon.match.falsy).replace(/ at.*/g, ""), "expected doSomething to be called with arguments " + "falsy\n doSomething(true)"); }, "assert.calledWith match.same exception message": function () { this.obj.doSomething(); assert.equals( this.message("calledWith", this.obj.doSomething, sinon.match.same(1)).replace(/ at.*/g, ""), "expected doSomething to be called with arguments same(1)\n doSomething()" ); }, "assert.calledWith match.typeOf exception message": function () { this.obj.doSomething(); var matcher = sinon.match.typeOf("string"); assert.equals( this.message("calledWith", this.obj.doSomething, matcher).replace(/ at.*/g, ""), "expected doSomething to be called with arguments typeOf(\"string\")\n doSomething()" ); }, "assert.calledWith match.instanceOf exception message": function () { this.obj.doSomething(); var matcher = sinon.match.instanceOf(function CustomType() {}); assert.equals( this.message("calledWith", this.obj.doSomething, matcher).replace(/ at.*/g, ""), "expected doSomething to be called with arguments instanceOf(CustomType)\n doSomething()" ); }, "assert.calledWith match object exception message": function () { this.obj.doSomething(); var matcher = sinon.match({ some: "value", and: 123 }); assert.equals( this.message("calledWith", this.obj.doSomething, matcher).replace(/ at.*/g, ""), "expected doSomething to be called with arguments match(some: value, and: 123)\n doSomething()" ); }, "assert.calledWith match boolean exception message": function () { this.obj.doSomething(); assert.equals(this.message("calledWith", this.obj.doSomething, sinon.match(true)).replace(/ at.*/g, ""), "expected doSomething to be called with arguments " + "match(true)\n doSomething()"); }, "assert.calledWith match number exception message": function () { this.obj.doSomething(); assert.equals(this.message("calledWith", this.obj.doSomething, sinon.match(123)).replace(/ at.*/g, ""), "expected doSomething to be called with arguments " + "match(123)\n doSomething()"); }, "assert.calledWith match string exception message": function () { this.obj.doSomething(); var matcher = sinon.match("Sinon"); assert.equals(this.message("calledWith", this.obj.doSomething, matcher).replace(/ at.*/g, ""), "expected doSomething to be called with arguments " + "match(\"Sinon\")\n doSomething()"); }, "assert.calledWith match regexp exception message": function () { this.obj.doSomething(); assert.equals( this.message("calledWith", this.obj.doSomething, sinon.match(/[a-z]+/)).replace(/ at.*/g, ""), "expected doSomething to be called with arguments match(/[a-z]+/)\n doSomething()" ); }, "assert.calledWith match test function exception message": function () { this.obj.doSomething(); var matcher = sinon.match({ test: function custom() {} }); assert.equals( this.message("calledWith", this.obj.doSomething, matcher).replace(/ at.*/g, ""), "expected doSomething to be called with arguments match(custom)\n doSomething()" ); }, "assert.calledWithMatch exception message": function () { this.obj.doSomething(1, 3, "hey"); assert.equals(this.message("calledWithMatch", this.obj.doSomething, 4, 3, "hey").replace(/ at.*/g, ""), "expected doSomething to be called with match 4, 3, " + "hey\n doSomething(1, 3, hey)"); }, "assert.alwaysCalledWith exception message": function () { this.obj.doSomething(1, 3, "hey"); this.obj.doSomething(1, "hey"); assert.equals(this.message("alwaysCalledWith", this.obj.doSomething, 1, "hey").replace(/ at.*/g, ""), "expected doSomething to always be called with arguments 1" + ", hey\n doSomething(1, 3, hey)\n doSomething(1, hey)"); }, "assert.alwaysCalledWithMatch exception message": function () { this.obj.doSomething(1, 3, "hey"); this.obj.doSomething(1, "hey"); assert.equals( this.message("alwaysCalledWithMatch", this.obj.doSomething, 1, "hey").replace(/ at.*/g, ""), "expected doSomething to always be called with match 1" + ", hey\n doSomething(1, 3, hey)\n doSomething(1, hey)" ); }, "assert.calledWithExactly exception message": function () { this.obj.doSomething(1, 3, "hey"); assert.equals(this.message("calledWithExactly", this.obj.doSomething, 1, 3).replace(/ at.*/g, ""), "expected doSomething to be called with exact arguments 1" + ", 3\n doSomething(1, 3, hey)"); }, "assert.alwaysCalledWithExactly exception message": function () { this.obj.doSomething(1, 3, "hey"); this.obj.doSomething(1, 3); assert.equals(this.message("alwaysCalledWithExactly", this.obj.doSomething, 1, 3).replace(/ at.*/g, ""), "expected doSomething to always be called with exact " + "arguments 1, 3\n doSomething(1, 3, hey)\n " + "doSomething(1, 3)"); }, "assert.neverCalledWith exception message": function () { this.obj.doSomething(1, 2, 3); assert.equals(this.message("neverCalledWith", this.obj.doSomething, 1, 2).replace(/ at.*/g, ""), "expected doSomething to never be called with " + "arguments 1, 2\n doSomething(1, 2, 3)"); }, "assert.neverCalledWithMatch exception message": function () { this.obj.doSomething(1, 2, 3); assert.equals(this.message("neverCalledWithMatch", this.obj.doSomething, 1, 2).replace(/ at.*/g, ""), "expected doSomething to never be called with match " + "1, 2\n doSomething(1, 2, 3)"); }, "assert.threw exception message": function () { this.obj.doSomething(1, 3, "hey"); this.obj.doSomething(1, 3); assert.equals(this.message("threw", this.obj.doSomething).replace(/ at.*/g, ""), "doSomething did not throw exception\n" + " doSomething(1, 3, hey)\n doSomething(1, 3)"); }, "assert.alwaysThrew exception message": function () { this.obj.doSomething(1, 3, "hey"); this.obj.doSomething(1, 3); assert.equals(this.message("alwaysThrew", this.obj.doSomething).replace(/ at.*/g, ""), "doSomething did not always throw exception\n" + " doSomething(1, 3, hey)\n doSomething(1, 3)"); }, "assert.match exception message": function () { assert.equals(this.message("match", { foo: 1 }, [1, 3]), "expected value to match\n" + " expected = [1, 3]\n" + " actual = { foo: 1 }"); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/buster-packaged.js000066400000000000000000000012051276775511300244650ustar00rootroot00000000000000var config = module.exports; config.packaged = { environment: "browser", rootPath: "../", libs: [ "node_modules/samsam/lib/samsam.js" ], sources: [ "pkg/sinon.js" ], testHelpers: [ "test/test-helper.js" ], tests: [ "test/**/*-test.js" ] }; // The sole purpose of this test setup is to // ensure that Sinon could be run inside of // a WebWorker config.webworkerSupport = { environment: "browser", rootPath: "../", sources: [ "pkg/sinon.js", "test/webworker-script.js" ], tests: [ "test/webworker-support-assessment.js" ] }; sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/buster.js000066400000000000000000000016001276775511300227270ustar00rootroot00000000000000var config = module.exports; config.browser = { environment: "browser", rootPath: "../", libs: [ "node_modules/lolex/lolex.js", "node_modules/samsam/lib/samsam.js", "node_modules/formatio/lib/formatio.js" ], sources: [ "lib/sinon.js", "lib/sinon/util/core.js", "lib/sinon/typeOf.js", "lib/**/*.js" ], testHelpers: [ "test/test-helper.js" ], tests: [ "test/**/*-test.js" ] }; config.coverage = { extends: "browser", "buster-istanbul": { outputDirectory: "coverage", format: "lcov", excludes: ["**/*.json"] }, extensions: [ require("buster-istanbul") ] }; config.node = { environment: "node", rootPath: "../", sources: [ "lib/sinon.js", "lib/**/*.js" ], tests: [ "test/**/*.js" ] }; sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/call-test.js000066400000000000000000001231041276775511300233170ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; var refute = buster.refute; function spyCallSetUp() { this.thisValue = {}; this.args = [{}, [], new Error(), 3]; this.returnValue = function () {}; this.call = sinon.spyCall(function () {}, this.thisValue, this.args, this.returnValue, null, 0); } function spyCallCallSetup() { this.args = []; this.proxy = sinon.spy(); this.call = sinon.spyCall(this.proxy, {}, this.args, null, null, 0); } function spyCallCalledTests(method) { return { setUp: spyCallSetUp, "returns true if all args match": function () { var args = this.args; assert(this.call[method](args[0], args[1], args[2])); }, "returns true if first args match": function () { var args = this.args; assert(this.call[method](args[0], args[1])); }, "returns true if first arg match": function () { var args = this.args; assert(this.call[method](args[0])); }, "returns true for no args": function () { assert(this.call[method]()); }, "returns false for too many args": function () { var args = this.args; assert.isFalse(this.call[method](args[0], args[1], args[2], args[3], {})); }, "returns false for wrong arg": function () { var args = this.args; assert.isFalse(this.call[method](args[0], args[2])); } }; } function spyCallNotCalledTests(method) { return { setUp: spyCallSetUp, "returns false if all args match": function () { var args = this.args; assert.isFalse(this.call[method](args[0], args[1], args[2])); }, "returns false if first args match": function () { var args = this.args; assert.isFalse(this.call[method](args[0], args[1])); }, "returns false if first arg match": function () { var args = this.args; assert.isFalse(this.call[method](args[0])); }, "returns false for no args": function () { assert.isFalse(this.call[method]()); }, "returns true for too many args": function () { var args = this.args; assert(this.call[method](args[0], args[1], args[2], args[3], {})); }, "returns true for wrong arg": function () { var args = this.args; assert(this.call[method](args[0], args[2])); } }; } buster.testCase("sinon.spy.call", { "call object": { setUp: spyCallSetUp, "gets call object": function () { var spy = sinon.spy.create(); spy(); var firstCall = spy.getCall(0); assert.isFunction(firstCall.calledOn); assert.isFunction(firstCall.calledWith); assert.isFunction(firstCall.returned); }, "stores given call id": function () { var call = sinon.spyCall(function () {}, {}, [], null, null, 42); assert.same(call.callId, 42); }, "throws if callId is undefined": function () { assert.exception(function () { sinon.spyCall.create(function () {}, {}, []); }); }, // This is actually a spy test: "records ascending call id's": function () { var spy = sinon.spy(); spy(); assert(this.call.callId < spy.getCall(0).callId); }, "exposes thisValue property": function () { var spy = sinon.spy(); var obj = {}; spy.call(obj); assert.same(spy.getCall(0).thisValue, obj); } }, "call calledOn": { setUp: spyCallSetUp, "calledOn should return true": function () { assert(this.call.calledOn(this.thisValue)); }, "calledOn should return false": function () { assert.isFalse(this.call.calledOn({})); } }, "call.calledWith": spyCallCalledTests("calledWith"), "call.calledWithMatch": spyCallCalledTests("calledWithMatch"), "call.notCalledWith": spyCallNotCalledTests("notCalledWith"), "call.notCalledWithMatch": spyCallNotCalledTests("notCalledWithMatch"), "call.calledWithExactly": { setUp: spyCallSetUp, "returns true when all args match": function () { var args = this.args; assert(this.call.calledWithExactly(args[0], args[1], args[2], args[3])); }, "returns false for too many args": function () { var args = this.args; assert.isFalse(this.call.calledWithExactly(args[0], args[1], args[2], args[3], {})); }, "returns false for too few args": function () { var args = this.args; assert.isFalse(this.call.calledWithExactly(args[0], args[1])); }, "returns false for unmatching args": function () { var args = this.args; assert.isFalse(this.call.calledWithExactly(args[0], args[1], args[1])); }, "returns true for no arguments": function () { var call = sinon.spyCall(function () {}, {}, [], null, null, 0); assert(call.calledWithExactly()); }, "returns false when called with no args but matching one": function () { var call = sinon.spyCall(function () {}, {}, [], null, null, 0); assert.isFalse(call.calledWithExactly({})); } }, "call.callArg": { setUp: spyCallCallSetup, "calls argument at specified index": function () { var callback = sinon.spy(); this.args.push(1, 2, callback); this.call.callArg(2); assert(callback.called); }, "throws if argument at specified index is not callable": function () { this.args.push(1); var call = this.call; assert.exception(function () { call.callArg(0); }, "TypeError"); }, "throws if no index is specified": function () { var call = this.call; assert.exception(function () { call.callArg(); }, "TypeError"); }, "throws if index is not number": function () { var call = this.call; assert.exception(function () { call.callArg({}); }, "TypeError"); } }, "call.callArgOn": { setUp: spyCallCallSetup, "calls argument at specified index": function () { var callback = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; this.args.push(1, 2, callback); this.call.callArgOn(2, thisObj); assert(callback.called); assert(callback.calledOn(thisObj)); }, "throws if argument at specified index is not callable": function () { var thisObj = { name1: "value1", name2: "value2" }; this.args.push(1); var call = this.call; assert.exception(function () { call.callArgOn(0, thisObj); }, "TypeError"); }, "throws if index is not number": function () { var thisObj = { name1: "value1", name2: "value2" }; var call = this.call; assert.exception(function () { call.callArgOn({}, thisObj); }, "TypeError"); } }, "call.callArgWith": { setUp: spyCallCallSetup, "calls argument at specified index with provided args": function () { var object = {}; var callback = sinon.spy(); this.args.push(1, callback); this.call.callArgWith(1, object); assert(callback.calledWith(object)); }, "calls callback without args": function () { var callback = sinon.spy(); this.args.push(1, callback); this.call.callArgWith(1); assert(callback.calledWith()); }, "calls callback wit multiple args": function () { var object = {}; var array = []; var callback = sinon.spy(); this.args.push(1, 2, callback); this.call.callArgWith(2, object, array); assert(callback.calledWith(object, array)); }, "throws if no index is specified": function () { var call = this.call; assert.exception(function () { call.callArgWith(); }, "TypeError"); }, "throws if index is not number": function () { var call = this.call; assert.exception(function () { call.callArgWith({}); }, "TypeError"); } }, "call.callArgOnWith": { setUp: spyCallCallSetup, "calls argument at specified index with provided args": function () { var object = {}; var thisObj = { name1: "value1", name2: "value2" }; var callback = sinon.spy(); this.args.push(1, callback); this.call.callArgOnWith(1, thisObj, object); assert(callback.calledWith(object)); assert(callback.calledOn(thisObj)); }, "calls callback without args": function () { var callback = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; this.args.push(1, callback); this.call.callArgOnWith(1, thisObj); assert(callback.calledWith()); assert(callback.calledOn(thisObj)); }, "calls callback with multiple args": function () { var object = {}; var array = []; var thisObj = { name1: "value1", name2: "value2" }; var callback = sinon.spy(); this.args.push(1, 2, callback); this.call.callArgOnWith(2, thisObj, object, array); assert(callback.calledWith(object, array)); assert(callback.calledOn(thisObj)); }, "throws if index is not number": function () { var thisObj = { name1: "value1", name2: "value2" }; var call = this.call; assert.exception(function () { call.callArgOnWith({}, thisObj); }, "TypeError"); } }, "call.yieldTest": { setUp: spyCallCallSetup, "invokes only argument as callback": function () { var callback = sinon.spy(); this.args.push(callback); this.call.yield(); assert(callback.calledOnce); assert.equals(callback.args[0].length, 0); }, "throws understandable error if no callback is passed": function () { var call = this.call; try { call.yield(); throw new Error(); } catch (e) { assert.equals(e.message, "spy cannot yield since no callback was passed."); } }, "includes stub name and actual arguments in error": function () { this.proxy.displayName = "somethingAwesome"; this.args.push(23, 42); var call = this.call; try { call.yield(); throw new Error(); } catch (e) { assert.equals(e.message, "somethingAwesome cannot yield since no callback was passed. " + "Received [23, 42]"); } }, "invokes last argument as callback": function () { var spy = sinon.spy(); this.args.push(24, {}, spy); this.call.yield(); assert(spy.calledOnce); assert.equals(spy.args[0].length, 0); }, "invokes first of two callbacks": function () { var spy = sinon.spy(); var spy2 = sinon.spy(); this.args.push(24, {}, spy, spy2); this.call.yield(); assert(spy.calledOnce); assert.isFalse(spy2.called); }, "invokes callback with arguments": function () { var obj = { id: 42 }; var spy = sinon.spy(); this.args.push(spy); this.call.yield(obj, "Crazy"); assert(spy.calledWith(obj, "Crazy")); }, "throws if callback throws": function () { this.args.push(function () { throw new Error("d'oh!"); }); var call = this.call; assert.exception(function () { call.yield(); }); } }, "call.invokeCallback": { "is alias for yield": function () { var call = sinon.spyCall(function () {}, {}, [], null, null, 0); assert.same(call.yield, call.invokeCallback); } }, "call.yieldOnTest": { setUp: spyCallCallSetup, "invokes only argument as callback": function () { var callback = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; this.args.push(callback); this.call.yieldOn(thisObj); assert(callback.calledOnce); assert(callback.calledOn(thisObj)); assert.equals(callback.args[0].length, 0); }, "throws understandable error if no callback is passed": function () { var call = this.call; var thisObj = { name1: "value1", name2: "value2" }; try { call.yieldOn(thisObj); throw new Error(); } catch (e) { assert.equals(e.message, "spy cannot yield since no callback was passed."); } }, "includes stub name and actual arguments in error": function () { this.proxy.displayName = "somethingAwesome"; this.args.push(23, 42); var call = this.call; var thisObj = { name1: "value1", name2: "value2" }; try { call.yieldOn(thisObj); throw new Error(); } catch (e) { assert.equals(e.message, "somethingAwesome cannot yield since no callback was passed. " + "Received [23, 42]"); } }, "invokes last argument as callback": function () { var spy = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; this.args.push(24, {}, spy); this.call.yieldOn(thisObj); assert(spy.calledOnce); assert.equals(spy.args[0].length, 0); assert(spy.calledOn(thisObj)); }, "invokes first of two callbacks": function () { var spy = sinon.spy(); var spy2 = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; this.args.push(24, {}, spy, spy2); this.call.yieldOn(thisObj); assert(spy.calledOnce); assert(spy.calledOn(thisObj)); assert.isFalse(spy2.called); }, "invokes callback with arguments": function () { var obj = { id: 42 }; var spy = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; this.args.push(spy); this.call.yieldOn(thisObj, obj, "Crazy"); assert(spy.calledWith(obj, "Crazy")); assert(spy.calledOn(thisObj)); }, "throws if callback throws": function () { this.args.push(function () { throw new Error("d'oh!"); }); var call = this.call; var thisObj = { name1: "value1", name2: "value2" }; assert.exception(function () { call.yieldOn(thisObj); }); } }, "call.yieldTo": { setUp: spyCallCallSetup, "invokes only argument as callback": function () { var callback = sinon.spy(); this.args.push({ success: callback }); this.call.yieldTo("success"); assert(callback.calledOnce); assert.equals(callback.args[0].length, 0); }, "throws understandable error if no callback is passed": function () { var call = this.call; try { call.yieldTo("success"); throw new Error(); } catch (e) { assert.equals(e.message, "spy cannot yield to 'success' since no callback was passed."); } }, "includes stub name and actual arguments in error": function () { this.proxy.displayName = "somethingAwesome"; this.args.push(23, 42); var call = this.call; try { call.yieldTo("success"); throw new Error(); } catch (e) { assert.equals( e.message, "somethingAwesome cannot yield to 'success' since no callback was passed. Received [23, 42]" ); } }, "invokes property on last argument as callback": function () { var spy = sinon.spy(); this.args.push(24, {}, { success: spy }); this.call.yieldTo("success"); assert(spy.calledOnce); assert.equals(spy.args[0].length, 0); }, "invokes first of two possible callbacks": function () { var spy = sinon.spy(); var spy2 = sinon.spy(); this.args.push(24, {}, { error: spy }, { error: spy2 }); this.call.yieldTo("error"); assert(spy.calledOnce); assert.isFalse(spy2.called); }, "invokes callback with arguments": function () { var obj = { id: 42 }; var spy = sinon.spy(); this.args.push({ success: spy }); this.call.yieldTo("success", obj, "Crazy"); assert(spy.calledWith(obj, "Crazy")); }, "throws if callback throws": function () { this.args.push({ success: function () { throw new Error("d'oh!"); } }); var call = this.call; assert.exception(function () { call.yieldTo("success"); }); } }, "call.yieldToOn": { setUp: spyCallCallSetup, "invokes only argument as callback": function () { var callback = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; this.args.push({ success: callback }); this.call.yieldToOn("success", thisObj); assert(callback.calledOnce); assert.equals(callback.args[0].length, 0); assert(callback.calledOn(thisObj)); }, "throws understandable error if no callback is passed": function () { var call = this.call; var thisObj = { name1: "value1", name2: "value2" }; try { call.yieldToOn("success", thisObj); throw new Error(); } catch (e) { assert.equals(e.message, "spy cannot yield to 'success' since no callback was passed."); } }, "includes stub name and actual arguments in error": function () { this.proxy.displayName = "somethingAwesome"; this.args.push(23, 42); var call = this.call; var thisObj = { name1: "value1", name2: "value2" }; try { call.yieldToOn("success", thisObj); throw new Error(); } catch (e) { assert.equals( e.message, "somethingAwesome cannot yield to 'success' since no callback was passed. Received [23, 42]" ); } }, "invokes property on last argument as callback": function () { var spy = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; this.args.push(24, {}, { success: spy }); this.call.yieldToOn("success", thisObj); assert(spy.calledOnce); assert(spy.calledOn(thisObj)); assert.equals(spy.args[0].length, 0); }, "invokes first of two possible callbacks": function () { var spy = sinon.spy(); var spy2 = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; this.args.push(24, {}, { error: spy }, { error: spy2 }); this.call.yieldToOn("error", thisObj); assert(spy.calledOnce); assert(spy.calledOn(thisObj)); assert.isFalse(spy2.called); }, "invokes callback with arguments": function () { var obj = { id: 42 }; var spy = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; this.args.push({ success: spy }); this.call.yieldToOn("success", thisObj, obj, "Crazy"); assert(spy.calledWith(obj, "Crazy")); assert(spy.calledOn(thisObj)); }, "throws if callback throws": function () { this.args.push({ success: function () { throw new Error("d'oh!"); } }); var call = this.call; var thisObj = { name1: "value1", name2: "value2" }; assert.exception(function () { call.yieldToOn("success", thisObj); }); } }, "call.toString": { setUp: function () { this.format = sinon.format; }, tearDown: function () { sinon.format = this.format; }, "includes spy name": function () { var object = { doIt: sinon.spy() }; object.doIt(); assert.equals(object.doIt.getCall(0).toString().replace(/ at.*/g, ""), "doIt()"); }, "includes single argument": function () { var object = { doIt: sinon.spy() }; object.doIt(42); assert.equals(object.doIt.getCall(0).toString().replace(/ at.*/g, ""), "doIt(42)"); }, "includes all arguments": function () { var object = { doIt: sinon.spy() }; object.doIt(42, "Hey"); assert.equals(object.doIt.getCall(0).toString().replace(/ at.*/g, ""), "doIt(42, Hey)"); }, "includes explicit return value": function () { var object = { doIt: sinon.stub().returns(42) }; object.doIt(42, "Hey"); assert.equals(object.doIt.getCall(0).toString().replace(/ at.*/g, ""), "doIt(42, Hey) => 42"); }, "includes empty string return value": function () { var object = { doIt: sinon.stub().returns("") }; object.doIt(42, "Hey"); assert.equals(object.doIt.getCall(0).toString().replace(/ at.*/g, ""), "doIt(42, Hey) => "); }, "includes exception": function () { var object = { doIt: sinon.stub().throws("TypeError") }; try { object.doIt(); } catch (e) {} // eslint-disable-line no-empty assert.equals(object.doIt.getCall(0).toString().replace(/ at.*/g, ""), "doIt() !TypeError"); }, "includes exception message if any": function () { var object = { doIt: sinon.stub().throws("TypeError", "Oh noes!") }; try { object.doIt(); } catch (e) {} // eslint-disable-line no-empty assert.equals(object.doIt.getCall(0).toString().replace(/ at.*/g, ""), "doIt() !TypeError(Oh noes!)"); }, "formats arguments with sinon.format": function () { sinon.format = sinon.stub().returns("Forty-two"); var object = { doIt: sinon.spy() }; object.doIt(42); assert.equals(object.doIt.getCall(0).toString().replace(/ at.*/g, ""), "doIt(Forty-two)"); assert(sinon.format.calledWith(42)); }, "formats return value with sinon.format": function () { sinon.format = sinon.stub().returns("Forty-two"); var object = { doIt: sinon.stub().returns(42) }; object.doIt(); assert.equals(object.doIt.getCall(0).toString().replace(/ at.*/g, ""), "doIt() => Forty-two"); assert(sinon.format.calledWith(42)); } }, constructor: { setUp: function () { this.CustomConstructor = function () {}; this.customPrototype = this.CustomConstructor.prototype; sinon.spy(this, "CustomConstructor"); }, "creates original object": function () { var myInstance = new this.CustomConstructor(); assert(this.customPrototype.isPrototypeOf(myInstance)); }, "does not interfere with instanceof": function () { var myInstance = new this.CustomConstructor(); assert(myInstance instanceof this.CustomConstructor); }, "records usage": function () { var myInstance = new this.CustomConstructor(); // eslint-disable-line no-unused-vars assert(this.CustomConstructor.called); } }, functions: { "throws if spying on non-existent property": function () { var myObj = {}; assert.exception(function () { sinon.spy(myObj, "ouch"); }); refute.defined(myObj.ouch); }, "throws if spying on non-existent object": function () { assert.exception(function () { sinon.spy(undefined, "ouch"); }); }, "haves toString method": function () { var obj = { meth: function () {} }; sinon.spy(obj, "meth"); assert.equals(obj.meth.toString(), "meth"); }, "toString should say 'spy' when unable to infer name": function () { var spy = sinon.spy(); assert.equals(spy.toString(), "spy"); }, "toString should report name of spied function": function () { function myTestFunc() {} var spy = sinon.spy(myTestFunc); assert.equals(spy.toString(), "myTestFunc"); }, "toString should prefer displayName property if available": function () { function myTestFunc() {} myTestFunc.displayName = "My custom method"; var spy = sinon.spy(myTestFunc); assert.equals(spy.toString(), "My custom method"); }, "toString should prefer property name if possible": function () { var obj = {}; obj.meth = sinon.spy(); obj.meth(); assert.equals(obj.meth.toString(), "meth"); } }, ".reset": (function () { function assertReset(spy) { assert(!spy.called); assert(!spy.calledOnce); assert.equals(spy.args.length, 0); assert.equals(spy.returnValues.length, 0); assert.equals(spy.exceptions.length, 0); assert.equals(spy.thisValues.length, 0); assert.isNull(spy.firstCall); assert.isNull(spy.secondCall); assert.isNull(spy.thirdCall); assert.isNull(spy.lastCall); } return { "resets spy state": function () { var spy = sinon.spy(); spy(); spy.reset(); assertReset(spy); }, "resets call order state": function () { var spies = [sinon.spy(), sinon.spy()]; spies[0](); spies[1](); spies[0].reset(); assert(!spies[0].calledBefore(spies[1])); }, "resets fakes returned by withArgs": function () { var spy = sinon.spy(); var fakeA = spy.withArgs("a"); var fakeB = spy.withArgs("b"); spy("a"); spy("b"); spy("c"); var fakeC = spy.withArgs("c"); spy.reset(); assertReset(fakeA); assertReset(fakeB); assertReset(fakeC); } }; }()), ".withArgs": { "defines withArgs method": function () { var spy = sinon.spy(); assert.isFunction(spy.withArgs); }, "records single call": function () { var spy = sinon.spy().withArgs(1); spy(1); assert.equals(spy.callCount, 1); }, "records non-matching call on original spy": function () { var spy = sinon.spy(); var argSpy = spy.withArgs(1); spy(1); spy(2); assert.equals(spy.callCount, 2); assert.equals(argSpy.callCount, 1); }, "records non-matching call with several arguments separately": function () { var spy = sinon.spy(); var argSpy = spy.withArgs(1, "str", {}); spy(1); spy(1, "str", {}); assert.equals(spy.callCount, 2); assert.equals(argSpy.callCount, 1); }, "records for partial argument match": function () { var spy = sinon.spy(); var argSpy = spy.withArgs(1, "str", {}); spy(1); spy(1, "str", {}); spy(1, "str", {}, []); assert.equals(spy.callCount, 3); assert.equals(argSpy.callCount, 2); }, "records filtered spy when original throws": function () { var spy = sinon.spy(function () { throw new Error("Oops"); }); var argSpy = spy.withArgs({}, []); assert.exception(function () { spy(1); }); assert.exception(function () { spy({}, []); }); assert.equals(spy.callCount, 2); assert.equals(argSpy.callCount, 1); }, "returns existing override for arguments": function () { var spy = sinon.spy(); var argSpy = spy.withArgs({}, []); var another = spy.withArgs({}, []); spy(); spy({}, []); spy({}, [], 2); assert.same(another, argSpy); refute.same(another, spy); assert.equals(spy.callCount, 3); assert.equals(spy.withArgs({}, []).callCount, 2); }, "chains withArgs calls on original spy": function () { var spy = sinon.spy(); var numArgSpy = spy.withArgs({}, []).withArgs(3); spy(); spy({}, []); spy(3); assert.equals(spy.callCount, 3); assert.equals(numArgSpy.callCount, 1); assert.equals(spy.withArgs({}, []).callCount, 1); }, "initializes filtered spy with callCount": function () { var spy = sinon.spy(); spy("a"); spy("b"); spy("b"); spy("c"); spy("c"); spy("c"); var argSpy1 = spy.withArgs("a"); var argSpy2 = spy.withArgs("b"); var argSpy3 = spy.withArgs("c"); assert.equals(argSpy1.callCount, 1); assert.equals(argSpy2.callCount, 2); assert.equals(argSpy3.callCount, 3); assert(argSpy1.called); assert(argSpy2.called); assert(argSpy3.called); assert(argSpy1.calledOnce); assert(argSpy2.calledTwice); assert(argSpy3.calledThrice); }, "initializes filtered spy with first, second, third and last call": function () { var spy = sinon.spy(); spy("a", 1); spy("b", 2); spy("b", 3); spy("b", 4); var argSpy1 = spy.withArgs("a"); var argSpy2 = spy.withArgs("b"); assert(argSpy1.firstCall.calledWithExactly("a", 1)); assert(argSpy1.lastCall.calledWithExactly("a", 1)); assert(argSpy2.firstCall.calledWithExactly("b", 2)); assert(argSpy2.secondCall.calledWithExactly("b", 3)); assert(argSpy2.thirdCall.calledWithExactly("b", 4)); assert(argSpy2.lastCall.calledWithExactly("b", 4)); }, "initializes filtered spy with arguments": function () { var spy = sinon.spy(); spy("a"); spy("b"); spy("b", "c", "d"); var argSpy1 = spy.withArgs("a"); var argSpy2 = spy.withArgs("b"); assert(argSpy1.getCall(0).calledWithExactly("a")); assert(argSpy2.getCall(0).calledWithExactly("b")); assert(argSpy2.getCall(1).calledWithExactly("b", "c", "d")); }, "initializes filtered spy with thisValues": function () { var spy = sinon.spy(); var thisValue1 = {}; var thisValue2 = {}; var thisValue3 = {}; spy.call(thisValue1, "a"); spy.call(thisValue2, "b"); spy.call(thisValue3, "b"); var argSpy1 = spy.withArgs("a"); var argSpy2 = spy.withArgs("b"); assert(argSpy1.getCall(0).calledOn(thisValue1)); assert(argSpy2.getCall(0).calledOn(thisValue2)); assert(argSpy2.getCall(1).calledOn(thisValue3)); }, "initializes filtered spy with return values": function () { var spy = sinon.spy(function (value) { return value; }); spy("a"); spy("b"); spy("b"); var argSpy1 = spy.withArgs("a"); var argSpy2 = spy.withArgs("b"); assert(argSpy1.getCall(0).returned("a")); assert(argSpy2.getCall(0).returned("b")); assert(argSpy2.getCall(1).returned("b")); }, "initializes filtered spy with call order": function () { var spy = sinon.spy(); spy("a"); spy("b"); spy("b"); var argSpy1 = spy.withArgs("a"); var argSpy2 = spy.withArgs("b"); assert(argSpy2.getCall(0).calledAfter(argSpy1.getCall(0))); assert(argSpy2.getCall(1).calledAfter(argSpy1.getCall(0))); }, "initializes filtered spy with exceptions": function () { var spy = sinon.spy(function (x, y) { var error = new Error(); error.name = y; throw error; }); /*eslint-disable no-empty*/ try { spy("a", "1"); } catch (ignored) {} try { spy("b", "2"); } catch (ignored) {} try { spy("b", "3"); } catch (ignored) {} /*eslint-enable no-empty*/ var argSpy1 = spy.withArgs("a"); var argSpy2 = spy.withArgs("b"); assert(argSpy1.getCall(0).threw("1")); assert(argSpy2.getCall(0).threw("2")); assert(argSpy2.getCall(1).threw("3")); } }, ".printf": { name: { named: function () { var named = sinon.spy(function cool() { }); assert.equals(named.printf("%n"), "cool"); }, anon: function () { var anon = sinon.spy(function () {}); assert.equals(anon.printf("%n"), "spy"); var noFn = sinon.spy(); assert.equals(noFn.printf("%n"), "spy"); } }, count: function () { // Throwing just to make sure it has no effect. var spy = sinon.spy(sinon.stub().throws()); function call() { try { spy(); } catch (e) {} // eslint-disable-line no-empty } call(); assert.equals(spy.printf("%c"), "once"); call(); assert.equals(spy.printf("%c"), "twice"); call(); assert.equals(spy.printf("%c"), "thrice"); call(); assert.equals(spy.printf("%c"), "4 times"); }, calls: { oneLine: function () { function test(arg, expected) { var spy = sinon.spy(); spy(arg); assert.equals(spy.printf("%C").replace(/ at.*/g, ""), "\n " + expected); } test(true, "spy(true)"); test(false, "spy(false)"); test(undefined, "spy(undefined)"); test(1, "spy(1)"); test(0, "spy(0)"); test(-1, "spy(-1)"); test(-1.1, "spy(-1.1)"); test(Infinity, "spy(Infinity)"); test(["a"], "spy([\"a\"])"); test({ a: "a" }, "spy({ a: \"a\" })"); }, multiline: function () { var str = "spy\ntest"; var spy = sinon.spy(); spy(str); spy(str); spy(str); assert.equals(spy.printf("%C").replace(/ at.*/g, ""), "\n spy(" + str + ")" + "\n\n spy(" + str + ")" + "\n\n spy(" + str + ")"); spy.reset(); spy("test"); spy("spy\ntest"); spy("spy\ntest"); assert.equals(spy.printf("%C").replace(/ at.*/g, ""), "\n spy(test)" + "\n spy(" + str + ")" + "\n\n spy(" + str + ")"); } }, thisValues: function () { var spy = sinon.spy(); spy(); assert.equals(spy.printf("%t"), "undefined"); spy.reset(); spy.call(true); assert.equals(spy.printf("%t"), "true"); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/collection-test.js000066400000000000000000000272241276775511300245450ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; buster.testCase("sinon.collection", { "creates fake collection": function () { var collection = sinon.create(sinon.collection); assert.isFunction(collection.verify); assert.isFunction(collection.restore); assert.isFunction(collection.verifyAndRestore); assert.isFunction(collection.stub); assert.isFunction(collection.mock); }, ".stub": { setUp: function () { this.stub = sinon.stub; this.collection = sinon.create(sinon.collection); }, tearDown: function () { sinon.stub = this.stub; }, "calls stub": function () { var object = { method: function () {} }; var args; sinon.stub = function () { args = Array.prototype.slice.call(arguments); }; this.collection.stub(object, "method"); assert.equals(args, [object, "method"]); }, "adds stub to fake array": function () { var object = { method: function () {} }; sinon.stub = function () { return object; }; this.collection.stub(object, "method"); assert.equals(this.collection.fakes, [object]); }, "appends stubs to fake array": function () { var objects = [{ id: 42 }, { id: 17 }]; var i = 0; sinon.stub = function () { return objects[i++]; }; this.collection.stub({ method: function () {} }, "method"); this.collection.stub({ method: function () {} }, "method"); assert.equals(this.collection.fakes, objects); }, "adds all object methods to fake array": function () { var object = { method: function () {}, method2: function () {} }; sinon.stub = function () { return object; }; this.collection.stub(object); assert.equals(this.collection.fakes, [object.method, object.method2]); assert.equals(this.collection.fakes.length, 2); }, "returns a stubbed object": function () { var object = { method: function () {} }; sinon.stub = function () { return object; }; assert.equals(this.collection.stub(object), object); }, "returns a stubbed method": function () { var object = { method: function () {} }; sinon.stub = function () { return object.method; }; assert.equals(this.collection.stub(object, "method"), object.method); }, "on node": { requiresSupportFor: { process: typeof process !== "undefined" }, setUp: function () { process.env.HELL = "Ain't too bad"; }, "stubs environment property": function () { this.collection.stub(process.env, "HELL", "froze over"); assert.equals(process.env.HELL, "froze over"); } } }, "stub anything": { setUp: function () { this.object = { property: 42 }; this.collection = sinon.create(sinon.collection); }, "stubs number property": function () { this.collection.stub(this.object, "property", 1); assert.equals(this.object.property, 1); }, "restores number property": function () { this.collection.stub(this.object, "property", 1); this.collection.restore(); assert.equals(this.object.property, 42); }, "fails if property does not exist": function () { var collection = this.collection; var object = {}; assert.exception(function () { collection.stub(object, "prop", 1); }); } }, ".mock": { setUp: function () { this.mock = sinon.mock; this.collection = sinon.create(sinon.collection); }, tearDown: function () { sinon.mock = this.mock; }, "calls mock": function () { var object = { id: 42 }; var args; sinon.mock = function () { args = Array.prototype.slice.call(arguments); }; this.collection.mock(object, "method"); assert.equals(args, [object, "method"]); }, "adds mock to fake array": function () { var object = { id: 42 }; sinon.mock = function () { return object; }; this.collection.mock(object, "method"); assert.equals(this.collection.fakes, [object]); }, "appends mocks to fake array": function () { var objects = [{ id: 42 }, { id: 17 }]; var i = 0; sinon.mock = function () { return objects[i++]; }; this.collection.mock({}, "method"); this.collection.mock({}, "method"); assert.equals(this.collection.fakes, objects); } }, "stub and mock test": { setUp: function () { this.mock = sinon.mock; this.stub = sinon.stub; this.collection = sinon.create(sinon.collection); }, tearDown: function () { sinon.mock = this.mock; sinon.stub = this.stub; }, "appends mocks and stubs to fake array": function () { var objects = [{ id: 42 }, { id: 17 }]; var i = 0; sinon.stub = sinon.mock = function () { return objects[i++]; }; this.collection.mock({ method: function () {} }, "method"); this.collection.stub({ method: function () {} }, "method"); assert.equals(this.collection.fakes, objects); } }, ".verify": { setUp: function () { this.collection = sinon.create(sinon.collection); }, "calls verify on all fakes": function () { this.collection.fakes = [{ verify: sinon.spy.create() }, { verify: sinon.spy.create() }]; this.collection.verify(); assert(this.collection.fakes[0].verify.called); assert(this.collection.fakes[1].verify.called); } }, ".restore": { setUp: function () { this.collection = sinon.create(sinon.collection); this.collection.fakes = [{ restore: sinon.spy.create() }, { restore: sinon.spy.create() }]; }, "calls restore on all fakes": function () { var fake0 = this.collection.fakes[0]; var fake1 = this.collection.fakes[1]; this.collection.restore(); assert(fake0.restore.called); assert(fake1.restore.called); }, "removes from collection when restored": function () { this.collection.restore(); assert(this.collection.fakes.length === 0); }, "restores functions when stubbing entire object": function () { var a = function () {}; var b = function () {}; var obj = { a: a, b: b }; this.collection.stub(obj); this.collection.restore(); assert.same(obj.a, a); assert.same(obj.b, b); } }, "verify and restore": { setUp: function () { this.collection = sinon.create(sinon.collection); }, "calls verify and restore": function () { this.collection.verify = sinon.spy.create(); this.collection.restore = sinon.spy.create(); this.collection.verifyAndRestore(); assert(this.collection.verify.called); assert(this.collection.restore.called); }, "throws when restore throws": function () { this.collection.verify = sinon.spy.create(); this.collection.restore = sinon.stub.create().throws(); assert.exception(function () { this.collection.verifyAndRestore(); }); }, "calls restore when restore throws": function () { this.collection.verify = sinon.spy.create(); this.collection.restore = sinon.stub.create().throws(); try { this.collection.verifyAndRestore(); } catch (e) {} // eslint-disable-line no-empty assert(this.collection.restore.called); } }, ".reset": { setUp: function () { this.collection = sinon.create(sinon.collection); this.collection.fakes = [{ reset: sinon.spy.create() }, { reset: sinon.spy.create() }]; }, "calls reset on all fakes": function () { var fake0 = this.collection.fakes[0]; var fake1 = this.collection.fakes[1]; this.collection.reset(); assert(fake0.reset.called); assert(fake1.reset.called); } }, "inject test": { setUp: function () { this.collection = sinon.create(sinon.collection); }, "injects fakes into object": function () { var obj = {}; this.collection.inject(obj); assert.isFunction(obj.spy); assert.isFunction(obj.stub); assert.isFunction(obj.mock); }, "returns argument": function () { var obj = {}; assert.same(this.collection.inject(obj), obj); }, "injects spy, stub, mock bound to collection": sinon.test(function () { var obj = {}; this.collection.inject(obj); this.stub(this.collection, "spy"); this.stub(this.collection, "stub"); this.stub(this.collection, "mock"); obj.spy(); var fn = obj.spy; fn(); obj.stub(); fn = obj.stub; fn(); obj.mock(); fn = obj.mock; fn(); assert(this.collection.spy.calledTwice); assert(this.collection.stub.calledTwice); assert(this.collection.mock.calledTwice); }) } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/extend-test.js000066400000000000000000000034171276775511300236770ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; buster.testCase("sinon.extend", { "should return unaltered target when only one argument": function () { var target = { hello: "world" }; sinon.extend(target); assert.equals(target, { hello: "world" }); }, "should copy all (own) properties into first argument, from all subsequent arguments": function () { var target = { hello: "world" }; sinon.extend(target, { a: "a" }, { b: "b" }); assert.equals(target.hello, "world"); assert.equals(target.a, "a"); assert.equals(target.b, "b"); }, "should copy toString method into target": function () { var target = { hello: "world", toString: function () { return "hello world"; } }; var source = { toString: function () { return "hello source"; } }; sinon.extend(target, source); assert.same(target.toString, source.toString); }, "must copy the last occuring property into the target": function () { var target = { a: 0, b: 0, c: 0, d: 0 }; var source1 = { a: 1, b: 1, c: 1 }; var source2 = { a: 2, b: 2 }; var source3 = { a: 3 }; sinon.extend(target, source1, source2, source3); assert.equals(target.a, 3); assert.equals(target.b, 2); assert.equals(target.c, 1); assert.equals(target.d, 0); } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/format-test.js000066400000000000000000000015111276775511300236710ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; buster.testCase("sinon.format", { "formats with formatio by default": function () { assert.equals(sinon.format({ id: 42 }), "{ id: 42 }"); }, "// should configure formatio to use maximum 250 entries": function () { // not sure how we can verify this integration with the current setup // where sinon.js calls formatio as part of it's loading // extracting sinon.format into a separate module would make this a lot // easier }, "formats strings without quotes": function () { assert.equals(sinon.format("Hey"), "Hey"); } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/hello-world-test.js000066400000000000000000000005331276775511300246340ustar00rootroot00000000000000// this is a very simple testcase primarily used for debugging // issues with the AMD setup (function (root) { "use strict"; var buster = root.buster || require("buster"); var assert = buster.assert; buster.testCase("hello world", { "hello world test": function () { assert(true); } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/issues/000077500000000000000000000000001276775511300224035ustar00rootroot00000000000000sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/issues/issues-test.js000066400000000000000000000146421276775511300252400ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../../lib/sinon"); var assert = buster.assert; var refute = buster.refute; buster.testCase("issues", { setUp: function () { this.sandbox = sinon.sandbox.create(); }, tearDown: function () { this.sandbox.restore(); }, "// #283": function () { function testSinonFakeTimersWith(interval, ticks) { var clock = sinon.useFakeTimers(); var spy = sinon.spy(); var id = setInterval(spy, interval); assert(!spy.calledOnce); clock.tick(ticks); assert(spy.calledOnce); clearInterval(id); clock.restore(); } // FAILS testSinonFakeTimersWith(10, 101); // PASS testSinonFakeTimersWith(99, 101); // FAILS testSinonFakeTimersWith(100, 200); // PASS testSinonFakeTimersWith(199, 200); // FAILS testSinonFakeTimersWith(500, 1001); // PASS testSinonFakeTimersWith(1000, 1001); }, "// #397": function () { var clock = sinon.useFakeTimers(); var cb2 = sinon.spy(); var cb1 = sinon.spy(function () { setTimeout(cb2, 0); }); setTimeout(cb1, 0); clock.tick(10); assert(cb1.called); assert(!cb2.called); clock.tick(10); assert(cb2.called); clock.restore(); }, "#458": { "on node": { requiresSupportFor: { process: typeof process !== "undefined" }, "stub out fs.readFileSync": function () { var fs = require("fs"); var testCase = this; refute.exception(function () { testCase.sandbox.stub(fs, "readFileSync"); }); } } }, "#624": { "//useFakeTimers should be idempotent": function () { // Issue #624 shows that useFakeTimers is not idempotent when it comes to // using Date.now // This test verifies that it's working, at least for Date.now var clock; clock = sinon.useFakeTimers(new Date("2014-12-29").getTime()); assert.equals(clock.now, Date.now()); clock = sinon.useFakeTimers(new Date("2015-12-15").getTime()); assert.equals(clock.now, Date.now()); clock = sinon.useFakeTimers(new Date("2015-1-5").getTime()); assert.equals(clock.now, Date.now()); } }, "#852 - createStubInstance on intherited constructors": { "must not throw error": function () { var A = function () {}; var B = function () {}; B.prototype = Object.create(A.prototype); B.prototype.constructor = A; refute.exception(function () { sinon.createStubInstance(B); }); } }, "#852(2) - createStubInstance should on same constructor": { "must be idempotent": function () { var A = function () {}; refute.exception(function () { sinon.createStubInstance(A); sinon.createStubInstance(A); }); } }, "#947 - sandbox.reset - prototype methods": { "should reset callCount": function () { function Car() {} Car.prototype.honk = function () { return "honk honk"; }; var sandbox = sinon.sandbox.create(); var car1 = new Car(); var car2 = new Car(); var honkSpy = sandbox.spy(car1, "honk"); var honkStub = sandbox.stub(car2, "honk"); car1.honk(); car2.honk(); assert.equals(honkSpy.callCount, 1); assert.equals(honkStub.callCount, 1); sandbox.reset(); assert.equals(car1.honk.callCount, 0); assert.equals(car2.honk.callCount, 0); sandbox.restore(); } }, "#947 - sandbox.reset - on instance methods": { "should reset callCount": function () { function Car() { this.honk = function () { return "honky honky"; }; } var sandbox = sinon.sandbox.create(); var car1 = new Car(); var car2 = new Car(); var honkSpy = sandbox.spy(car1, "honk"); var honkStub = sandbox.stub(car2, "honk"); honkStub.returns("forty two"); car1.honk(); car2.honk(); assert.equals(honkSpy.callCount, 1); assert.equals(honkStub.callCount, 1); sandbox.reset(); assert.equals(car1.honk.callCount, 0); assert.equals(car2.honk.callCount, 0); sandbox.restore(); } }, "#947 - sandbox.reset - on literal object members": { "should reset callCount": function () { var car = { honk: function () { return "honker"; }, honky: function () { return "honkity honk"; } }; var sandbox = sinon.sandbox.create(); var honkSpy = sandbox.spy(car, "honk"); var honkStub = sandbox.stub(car, "honky", function () { return 42; }); car.honk(); car.honky(); assert.equals(honkSpy.callCount, 1); assert.equals(honkStub.callCount, 1); sandbox.reset(); assert.equals(car.honk.callCount, 0); assert.equals(car.honky.callCount, 0); sandbox.restore(); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/log-error-test.js000066400000000000000000000067341276775511300243250ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; var refute = buster.refute; buster.testCase("sinon.log", { "is a function": function () { assert.isFunction(sinon.log); } }); buster.testCase("sinon.logError", { setUp: function () { this.sandbox = sinon.sandbox.create(); this.timeOutStub = this.sandbox.stub(sinon.logError, "setTimeout"); }, tearDown: function () { // setTimeout = realSetTimeout; this.sandbox.restore(); }, "is a function": function () { assert.isFunction(sinon.logError); }, "calls sinon.log with a String": function () { var spy = this.sandbox.spy(sinon, "log"); var name = "Quisque consequat, elit id suscipit."; var message = "Pellentesque gravida orci in tellus tristique, ac commodo nibh congue."; var error = new Error(); error.name = name; error.message = message; sinon.logError("a label", error); assert(spy.called); assert(spy.calledWithMatch(name)); assert(spy.calledWithMatch(message)); }, "calls sinon.log with a stack": function () { var spy = this.sandbox.spy(sinon, "log"); var stack = "Integer rutrum dictum elit, posuere accumsan nisi pretium vel. Phasellus adipiscing."; var error = new Error(); error.stack = stack; sinon.logError("another label", error); assert(spy.called); assert(spy.calledWithMatch(stack)); }, "should call logError.setTimeout": function () { var error = new Error(); sinon.logError("some wonky label", error); assert(this.timeOutStub.calledOnce); }, "should pass a throwing function to logError.setTimeout": function () { var error = new Error(); sinon.logError("async error", error); var func = this.timeOutStub.args[0][0]; assert.exception(func); } }); buster.testCase("sinon.logError.useImmediateExceptions", { setUp: function () { this.sandbox = sinon.sandbox.create(); this.timeOutStub = this.sandbox.stub(sinon.logError, "setTimeout"); this.originalFlag = sinon.logError.useImmediateExceptions; }, tearDown: function () { // setTimeout = realSetTimeout; this.sandbox.restore(); sinon.logError.useImmediateExceptions = this.originalFlag; }, "throws the logged error immediately, does not call logError.setTimeout when flag is true": function () { var error = new Error(); sinon.logError.useImmediateExceptions = true; assert.exception(function () { sinon.logError("an error", error); }); assert(this.timeOutStub.notCalled); }, "does not throw logged error immediately and calls logError.setTimeout when flag is false": function () { var error = new Error(); sinon.logError.useImmediateExceptions = false; refute.exception(function () { sinon.logError("an error", error); }); assert(this.timeOutStub.called); } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/match-test.js000066400000000000000000000535461276775511300235140ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; function propertyMatcherTests(matcher) { return { "returns matcher": function () { var has = matcher("foo"); assert(sinon.match.isMatcher(has)); }, "throws if first argument is not string": function () { assert.exception(function () { matcher(); }, "TypeError"); assert.exception(function () { matcher(123); }, "TypeError"); }, "returns false if value is undefined or null": function () { var has = matcher("foo"); assert.isFalse(has.test(undefined)); assert.isFalse(has.test(null)); }, "returns true if object has property": function () { var has = matcher("foo"); assert(has.test({ foo: null })); }, "returns false if object value is not equal to given value": function () { var has = matcher("foo", 1); assert.isFalse(has.test({ foo: null })); }, "returns true if object value is equal to given value": function () { var has = matcher("message", "sinon rocks"); assert(has.test({ message: "sinon rocks" })); assert(has.test(new Error("sinon rocks"))); }, "returns true if string property matches": function () { var has = matcher("length", 5); assert(has.test("sinon")); }, "allows to expect undefined": function () { var has = matcher("foo", undefined); assert.isFalse(has.test({ foo: 1 })); }, "compares value deeply": function () { var has = matcher("foo", { bar: "doo", test: 42 }); assert(has.test({ foo: { bar: "doo", test: 42 } })); }, "compares with matcher": function () { var has = matcher("callback", sinon.match.typeOf("function")); assert(has.test({ callback: function () {} })); } }; } buster.testCase("sinon.match", { "returns matcher": function () { var match = sinon.match(function () {}); assert(sinon.match.isMatcher(match)); }, "exposes test function": function () { var test = function () {}; var match = sinon.match(test); assert.same(match.test, test); }, "returns true if properties are equal": function () { var match = sinon.match({ str: "sinon", nr: 1 }); assert(match.test({ str: "sinon", nr: 1, other: "ignored" })); }, "returns true if properties are deep equal": function () { var match = sinon.match({ deep: { str: "sinon" } }); assert(match.test({ deep: { str: "sinon", ignored: "value" } })); }, "returns false if a property is not equal": function () { var match = sinon.match({ str: "sinon", nr: 1 }); assert.isFalse(match.test({ str: "sinon", nr: 2 })); }, "returns false if a property is missing": function () { var match = sinon.match({ str: "sinon", nr: 1 }); assert.isFalse(match.test({ nr: 1 })); }, "returns true if array is equal": function () { var match = sinon.match({ arr: ["a", "b"] }); assert(match.test({ arr: ["a", "b"] })); }, "returns false if array is not equal": function () { var match = sinon.match({ arr: ["b", "a"] }); assert.isFalse(match.test({ arr: ["a", "b"] })); }, "returns true if number objects are equal": function () { /*eslint-disable no-new-wrappers*/ var match = sinon.match({ one: new Number(1) }); assert(match.test({ one: new Number(1) })); /*eslint-enable no-new-wrappers*/ }, "returns true if test matches": function () { var match = sinon.match({ prop: sinon.match.typeOf("boolean") }); assert(match.test({ prop: true })); }, "returns false if test does not match": function () { var match = sinon.match({ prop: sinon.match.typeOf("boolean") }); assert.isFalse(match.test({ prop: "no" })); }, "returns true if deep test matches": function () { var match = sinon.match({ deep: { prop: sinon.match.typeOf("boolean") } }); assert(match.test({ deep: { prop: true } })); }, "returns false if deep test does not match": function () { var match = sinon.match({ deep: { prop: sinon.match.typeOf("boolean") } }); assert.isFalse(match.test({ deep: { prop: "no" } })); }, "returns false if tested value is null or undefined": function () { var match = sinon.match({}); assert.isFalse(match.test(null)); assert.isFalse(match.test(undefined)); }, "returns true if error message matches": function () { var match = sinon.match({ message: "evil error" }); assert(match.test(new Error("evil error"))); }, "returns true if string property matches": function () { var match = sinon.match({ length: 5 }); assert(match.test("sinon")); }, "returns true if number property matches": function () { var match = sinon.match({ toFixed: sinon.match.func }); assert(match.test(0)); }, "returns true for string match": function () { var match = sinon.match("sinon"); assert(match.test("sinon")); }, "returns true for substring match": function () { var match = sinon.match("no"); assert(match.test("sinon")); }, "returns false for string mismatch": function () { var match = sinon.match("Sinon.JS"); assert.isFalse(match.test(null)); assert.isFalse(match.test({})); assert.isFalse(match.test("sinon")); assert.isFalse(match.test("sinon.js")); }, "returns true for regexp match": function () { var match = sinon.match(/^[sino]+$/); assert(match.test("sinon")); }, "returns false for regexp string mismatch": function () { var match = sinon.match(/^[sin]+$/); assert.isFalse(match.test("sinon")); }, "returns false for regexp type mismatch": function () { var match = sinon.match(/.*/); assert.isFalse(match.test()); assert.isFalse(match.test(null)); assert.isFalse(match.test(123)); assert.isFalse(match.test({})); }, "returns true for number match": function () { var match = sinon.match(1); assert(match.test(1)); assert(match.test("1")); assert(match.test(true)); }, "returns false for number mismatch": function () { var match = sinon.match(1); assert.isFalse(match.test()); assert.isFalse(match.test(null)); assert.isFalse(match.test(2)); assert.isFalse(match.test(false)); assert.isFalse(match.test({})); }, "returns true if test function in object returns true": function () { var match = sinon.match({ test: function () { return true; }}); assert(match.test()); }, "returns false if test function in object returns false": function () { var match = sinon.match({ test: function () { return false; }}); assert.isFalse(match.test()); }, "returns false if test function in object returns nothing": function () { var match = sinon.match({ test: function () {}}); assert.isFalse(match.test()); }, "passes actual value to test function in object": function () { var match = sinon.match({ test: function (arg) { return arg; }}); assert(match.test(true)); }, "uses matcher": function () { var match = sinon.match(sinon.match("test")); assert(match.test("testing")); }, ".toString": { "returns message": function () { var message = "hello sinon.match"; var match = sinon.match(function () {}, message); assert.same(match.toString(), message); }, "defaults to match(functionName)": function () { var match = sinon.match(function custom() {}); assert.same(match.toString(), "match(custom)"); } }, ".any": { "is matcher": function () { assert(sinon.match.isMatcher(sinon.match.any)); }, "returns true when tested": function () { assert(sinon.match.any.test()); } }, ".defined": { "is matcher": function () { assert(sinon.match.isMatcher(sinon.match.defined)); }, "returns false if test is called with null": function () { assert.isFalse(sinon.match.defined.test(null)); }, "returns false if test is called with undefined": function () { assert.isFalse(sinon.match.defined.test(undefined)); }, "returns true if test is called with any value": function () { assert(sinon.match.defined.test(false)); assert(sinon.match.defined.test(true)); assert(sinon.match.defined.test(0)); assert(sinon.match.defined.test(1)); assert(sinon.match.defined.test("")); }, "returns true if test is called with any object": function () { assert(sinon.match.defined.test({})); assert(sinon.match.defined.test(function () {})); } }, ".truthy": { "is matcher": function () { assert(sinon.match.isMatcher(sinon.match.truthy)); }, "returns true if test is called with trueish value": function () { assert(sinon.match.truthy.test(true)); assert(sinon.match.truthy.test(1)); assert(sinon.match.truthy.test("yes")); }, "returns false if test is called falsy value": function () { assert.isFalse(sinon.match.truthy.test(false)); assert.isFalse(sinon.match.truthy.test(null)); assert.isFalse(sinon.match.truthy.test(undefined)); assert.isFalse(sinon.match.truthy.test("")); } }, ".falsy": { "is matcher": function () { assert(sinon.match.isMatcher(sinon.match.falsy)); }, "returns true if test is called falsy value": function () { assert(sinon.match.falsy.test(false)); assert(sinon.match.falsy.test(null)); assert(sinon.match.falsy.test(undefined)); assert(sinon.match.falsy.test("")); }, "returns false if test is called with trueish value": function () { assert.isFalse(sinon.match.falsy.test(true)); assert.isFalse(sinon.match.falsy.test(1)); assert.isFalse(sinon.match.falsy.test("yes")); } }, ".same": { "returns matcher": function () { var same = sinon.match.same(); assert(sinon.match.isMatcher(same)); }, "returns true if test is called with same argument": function () { var object = {}; var same = sinon.match.same(object); assert(same.test(object)); }, "returns false if test is not called with same argument": function () { var same = sinon.match.same({}); assert.isFalse(same.test({})); } }, ".typeOf": { "throws if given argument is not a string": function () { assert.exception(function () { sinon.match.typeOf(); }, "TypeError"); assert.exception(function () { sinon.match.typeOf(123); }, "TypeError"); }, "returns matcher": function () { var typeOf = sinon.match.typeOf("string"); assert(sinon.match.isMatcher(typeOf)); }, "returns true if test is called with string": function () { var typeOf = sinon.match.typeOf("string"); assert(typeOf.test("Sinon.JS")); }, "returns false if test is not called with string": function () { var typeOf = sinon.match.typeOf("string"); assert.isFalse(typeOf.test(123)); }, "returns true if test is called with regexp": function () { var typeOf = sinon.match.typeOf("regexp"); assert(typeOf.test(/.+/)); }, "returns false if test is not called with regexp": function () { var typeOf = sinon.match.typeOf("regexp"); assert.isFalse(typeOf.test(true)); } }, ".instanceOf": { "throws if given argument is not a function": function () { assert.exception(function () { sinon.match.instanceOf(); }, "TypeError"); assert.exception(function () { sinon.match.instanceOf("foo"); }, "TypeError"); }, "returns matcher": function () { var instanceOf = sinon.match.instanceOf(function () {}); assert(sinon.match.isMatcher(instanceOf)); }, "returns true if test is called with instance of argument": function () { var instanceOf = sinon.match.instanceOf(Array); assert(instanceOf.test([])); }, "returns false if test is not called with instance of argument": function () { var instanceOf = sinon.match.instanceOf(Array); assert.isFalse(instanceOf.test({})); } }, ".has": propertyMatcherTests(sinon.match.has), ".hasOwn": propertyMatcherTests(sinon.match.hasOwn), ".hasSpecial": { "returns true if object has inherited property": function () { var has = sinon.match.has("toString"); assert(has.test({})); }, "only includes property in message": function () { var has = sinon.match.has("test"); assert.equals(has.toString(), "has(\"test\")"); }, "includes property and value in message": function () { var has = sinon.match.has("test", undefined); assert.equals(has.toString(), "has(\"test\", undefined)"); }, "returns true if string function matches": function () { var has = sinon.match.has("toUpperCase", sinon.match.func); assert(has.test("sinon")); }, "returns true if number function matches": function () { var has = sinon.match.has("toFixed", sinon.match.func); assert(has.test(0)); } }, ".hasOwnSpecial": { "returns false if object has inherited property": function () { var hasOwn = sinon.match.hasOwn("toString"); assert.isFalse(hasOwn.test({})); }, "only includes property in message": function () { var hasOwn = sinon.match.hasOwn("test"); assert.equals(hasOwn.toString(), "hasOwn(\"test\")"); }, "includes property and value in message": function () { var hasOwn = sinon.match.hasOwn("test", undefined); assert.equals(hasOwn.toString(), "hasOwn(\"test\", undefined)"); } }, ".bool": { "is typeOf boolean matcher": function () { var bool = sinon.match.bool; assert(sinon.match.isMatcher(bool)); assert.equals(bool.toString(), "typeOf(\"boolean\")"); } }, ".number": { "is typeOf number matcher": function () { var number = sinon.match.number; assert(sinon.match.isMatcher(number)); assert.equals(number.toString(), "typeOf(\"number\")"); } }, ".string": { "is typeOf string matcher": function () { var string = sinon.match.string; assert(sinon.match.isMatcher(string)); assert.equals(string.toString(), "typeOf(\"string\")"); } }, ".object": { "is typeOf object matcher": function () { var object = sinon.match.object; assert(sinon.match.isMatcher(object)); assert.equals(object.toString(), "typeOf(\"object\")"); } }, ".func": { "is typeOf function matcher": function () { var func = sinon.match.func; assert(sinon.match.isMatcher(func)); assert.equals(func.toString(), "typeOf(\"function\")"); } }, ".array": { "is typeOf array matcher": function () { var array = sinon.match.array; assert(sinon.match.isMatcher(array)); assert.equals(array.toString(), "typeOf(\"array\")"); } }, ".regexp": { "is typeOf regexp matcher": function () { var regexp = sinon.match.regexp; assert(sinon.match.isMatcher(regexp)); assert.equals(regexp.toString(), "typeOf(\"regexp\")"); } }, ".date": { "is typeOf regexp matcher": function () { var date = sinon.match.date; assert(sinon.match.isMatcher(date)); assert.equals(date.toString(), "typeOf(\"date\")"); } }, ".or": { "is matcher": function () { var numberOrString = sinon.match.number.or(sinon.match.string); assert(sinon.match.isMatcher(numberOrString)); assert.equals(numberOrString.toString(), "typeOf(\"number\").or(typeOf(\"string\"))"); }, "requires matcher argument": function () { assert.exception(function () { sinon.match.instanceOf(Error).or(); }, "TypeError"); }, "will coerce argument to matcher": function () { var abcOrDef = sinon.match("abc").or("def"); assert(sinon.match.isMatcher(abcOrDef)); assert.equals(abcOrDef.toString(), "match(\"abc\").or(match(\"def\"))"); }, "returns true if either matcher matches": function () { var numberOrString = sinon.match.number.or(sinon.match.string); assert(numberOrString.test(123)); assert(numberOrString.test("abc")); }, "returns false if neither matcher matches": function () { var numberOrAbc = sinon.match.number.or("abc"); assert.isFalse(numberOrAbc.test(/.+/)); assert.isFalse(numberOrAbc.test(new Date())); assert.isFalse(numberOrAbc.test({})); }, "can be used with undefined": function () { var numberOrUndef = sinon.match.number.or(undefined); assert(numberOrUndef.test(123)); assert(numberOrUndef.test(undefined)); } }, ".and": { "is matcher": function () { var fooAndBar = sinon.match.has("foo").and(sinon.match.has("bar")); assert(sinon.match.isMatcher(fooAndBar)); assert.equals(fooAndBar.toString(), "has(\"foo\").and(has(\"bar\"))"); }, "requires matcher argument": function () { assert.exception(function () { sinon.match.instanceOf(Error).and(); }, "TypeError"); }, "will coerce to matcher": function () { var abcOrObj = sinon.match("abc").or({a: 1}); assert(sinon.match.isMatcher(abcOrObj)); assert.equals(abcOrObj.toString(), "match(\"abc\").or(match(a: 1))"); }, "returns true if both matchers match": function () { var fooAndBar = sinon.match.has("foo").and({ bar: "bar" }); assert(fooAndBar.test({ foo: "foo", bar: "bar" })); }, "returns false if either matcher does not match": function () { var fooAndBar = sinon.match.has("foo").and(sinon.match.has("bar")); assert.isFalse(fooAndBar.test({ foo: "foo" })); assert.isFalse(fooAndBar.test({ bar: "bar" })); }, "can be used with undefined": function () { var falsyAndUndefined = sinon.match.falsy.and(undefined); assert.isFalse(falsyAndUndefined.test(false)); assert(falsyAndUndefined.test(undefined)); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/mock-test.js000066400000000000000000001023311276775511300233340ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; var refute = buster.refute; buster.testCase("sinon.mock", { ".create": { "returns function with expects method": function () { var mock = sinon.mock.create({}); assert.isFunction(mock.expects); }, "throws without object": function () { assert.exception(function () { sinon.mock.create(); }, "TypeError"); } }, ".expects": { setUp: function () { this.mock = sinon.mock.create({ someMethod: function () {} }); }, "throws without method": function () { var mock = this.mock; assert.exception(function () { mock.expects(); }, "TypeError"); }, "returns expectation": function () { var result = this.mock.expects("someMethod"); assert.isFunction(result); assert.equals(result.method, "someMethod"); }, "throws if expecting a non-existent method": function () { var mock = this.mock; assert.exception(function () { mock.expects("someMethod2"); }); } }, ".expectation": { setUp: function () { this.method = "myMeth"; this.expectation = sinon.expectation.create(this.method); }, "creates unnamed expectation": function () { var anonMock = sinon.expectation.create(); anonMock.never(); assert(anonMock.verify()); }, "uses 'anonymous mock expectation' for unnamed expectation": function () { var anonMock = sinon.expectation.create(); anonMock.once(); try { anonMock.verify(); } catch (e) { assert.match(e.message, "anonymous mock expectation"); } }, "call expectation": function () { this.expectation(); assert.isFunction(this.expectation.invoke); assert(this.expectation.called); }, "is invokable": function () { var expectation = this.expectation; refute.exception(function () { expectation(); }); }, ".returns": { "returns configured return value": function () { var object = {}; this.expectation.returns(object); assert.same(this.expectation(), object); } }, call: { "is called with correct this value": function () { var object = { method: this.expectation }; object.method(); assert(this.expectation.calledOn(object)); } }, ".callCount": { "onlys be invokable once by default": function () { var expectation = this.expectation; expectation(); assert.exception(function () { expectation(); }, "ExpectationError"); }, "throw readable error": function () { var expectation = this.expectation; expectation(); try { expectation(); buster.referee.fail("Expected to throw"); } catch (e) { assert.equals(e.message, "myMeth already called once"); } } }, ".callCountNever": { "is not callable": function () { var expectation = this.expectation; expectation.never(); assert.exception(function () { expectation(); }, "ExpectationError"); }, "returns expectation for chaining": function () { assert.same(this.expectation.never(), this.expectation); } }, ".callCountOnce": { "allows one call": function () { var expectation = this.expectation; expectation.once(); expectation(); assert.exception(function () { expectation(); }, "ExpectationError"); }, "returns expectation for chaining": function () { assert.same(this.expectation.once(), this.expectation); } }, ".callCountTwice": { "allows two calls": function () { var expectation = this.expectation; expectation.twice(); expectation(); expectation(); assert.exception(function () { expectation(); }, "ExpectationError"); }, "returns expectation for chaining": function () { assert.same(this.expectation.twice(), this.expectation); } }, ".callCountThrice": { "allows three calls": function () { var expectation = this.expectation; expectation.thrice(); expectation(); expectation(); expectation(); assert.exception(function () { expectation(); }, "ExpectationError"); }, "returns expectation for chaining": function () { assert.same(this.expectation.thrice(), this.expectation); } }, ".callCountExactly": { "allows specified number of calls": function () { var expectation = this.expectation; expectation.exactly(2); expectation(); expectation(); assert.exception(function () { expectation(); }, "ExpectationError"); }, "returns expectation for chaining": function () { assert.same(this.expectation.exactly(2), this.expectation); }, "throws without argument": function () { var expectation = this.expectation; assert.exception(function () { expectation.exactly(); }, "TypeError"); }, "throws without number": function () { var expectation = this.expectation; assert.exception(function () { expectation.exactly("12"); }, "TypeError"); } }, ".atLeast": { "throws without argument": function () { var expectation = this.expectation; assert.exception(function () { expectation.atLeast(); }, "TypeError"); }, "throws without number": function () { var expectation = this.expectation; assert.exception(function () { expectation.atLeast({}); }, "TypeError"); }, "returns expectation for chaining": function () { assert.same(this.expectation.atLeast(2), this.expectation); }, "allows any number of calls": function () { var expectation = this.expectation; expectation.atLeast(2); expectation(); expectation(); refute.exception(function () { expectation(); expectation(); }); }, "should not be met with too few calls": function () { this.expectation.atLeast(2); this.expectation(); assert.isFalse(this.expectation.met()); }, "is met with exact calls": function () { this.expectation.atLeast(2); this.expectation(); this.expectation(); assert(this.expectation.met()); }, "is met with excessive calls": function () { this.expectation.atLeast(2); this.expectation(); this.expectation(); this.expectation(); assert(this.expectation.met()); }, "should not throw when exceeding at least expectation": function () { var obj = { foobar: function () {} }; var mock = sinon.mock(obj); mock.expects("foobar").atLeast(1); obj.foobar(); refute.exception(function () { obj.foobar(); mock.verify(); }); }, "should not throw when exceeding at least expectation and withargs": function () { var obj = { foobar: function () {} }; var mock = sinon.mock(obj); mock.expects("foobar").withArgs("arg1"); mock.expects("foobar").atLeast(1).withArgs("arg2"); obj.foobar("arg1"); obj.foobar("arg2"); obj.foobar("arg2"); assert(mock.verify()); } }, ".atMost": { "throws without argument": function () { var expectation = this.expectation; assert.exception(function () { expectation.atMost(); }, "TypeError"); }, "throws without number": function () { var expectation = this.expectation; assert.exception(function () { expectation.atMost({}); }, "TypeError"); }, "returns expectation for chaining": function () { assert.same(this.expectation.atMost(2), this.expectation); }, "allows fewer calls": function () { var expectation = this.expectation; expectation.atMost(2); refute.exception(function () { expectation(); }); }, "is met with fewer calls": function () { this.expectation.atMost(2); this.expectation(); assert(this.expectation.met()); }, "is met with exact calls": function () { this.expectation.atMost(2); this.expectation(); this.expectation(); assert(this.expectation.met()); }, "should not be met with excessive calls": function () { var expectation = this.expectation; this.expectation.atMost(2); this.expectation(); this.expectation(); assert.exception(function () { expectation(); }, "ExpectationError"); assert.isFalse(this.expectation.met()); } }, ".atMostAndAtLeast": { setUp: function () { this.expectation.atLeast(2); this.expectation.atMost(3); }, "should not be met with too few calls": function () { this.expectation(); assert.isFalse(this.expectation.met()); }, "is met with minimum calls": function () { this.expectation(); this.expectation(); assert(this.expectation.met()); }, "is met with maximum calls": function () { this.expectation(); this.expectation(); this.expectation(); assert(this.expectation.met()); }, "throws with excessive calls": function () { var expectation = this.expectation; expectation(); expectation(); expectation(); assert.exception(function () { expectation(); }, "ExpectationError"); } }, ".met": { "should not be met when not called enough times": function () { assert.isFalse(this.expectation.met()); }, "is met when called enough times": function () { this.expectation(); assert(this.expectation.met()); }, "should not be met when called too many times": function () { this.expectation(); try { this.expectation(); } catch (e) {} // eslint-disable-line no-empty assert.isFalse(this.expectation.met()); } }, ".withArgs": { "returns expectation for chaining": function () { assert.same(this.expectation.withArgs(1), this.expectation); }, "accepts call with expected args": function () { this.expectation.withArgs(1, 2, 3); this.expectation(1, 2, 3); assert(this.expectation.met()); }, "throws when called without args": function () { var expectation = this.expectation; expectation.withArgs(1, 2, 3); assert.exception(function () { expectation(); }, "ExpectationError"); }, "throws when called with too few args": function () { var expectation = this.expectation; expectation.withArgs(1, 2, 3); assert.exception(function () { expectation(1, 2); }, "ExpectationError"); }, "throws when called with wrong args": function () { var expectation = this.expectation; expectation.withArgs(1, 2, 3); assert.exception(function () { expectation(2, 2, 3); }, "ExpectationError"); }, "allows excessive args": function () { var expectation = this.expectation; expectation.withArgs(1, 2, 3); refute.exception(function () { expectation(1, 2, 3, 4); }); }, "calls accept with no args": function () { this.expectation.withArgs(); this.expectation(); assert(this.expectation.met()); }, "allows no args called with excessive args": function () { var expectation = this.expectation; expectation.withArgs(); refute.exception(function () { expectation(1, 2, 3); }); }, "works with sinon matchers": function () { this.expectation.withArgs(sinon.match.number, sinon.match.string, sinon.match.func); this.expectation(1, "test", function () {}); assert(this.expectation.met()); }, "throws when sinon matchers fail": function () { var expectation = this.expectation; this.expectation.withArgs(sinon.match.number, sinon.match.string, sinon.match.func); assert.exception(function () { expectation(1, 2, 3); }, "ExpectationError"); } }, ".withExactArgs": { "returns expectation for chaining": function () { assert.same(this.expectation.withExactArgs(1), this.expectation); }, "accepts call with expected args": function () { this.expectation.withExactArgs(1, 2, 3); this.expectation(1, 2, 3); assert(this.expectation.met()); }, "throws when called without args": function () { var expectation = this.expectation; expectation.withExactArgs(1, 2, 3); assert.exception(function () { expectation(); }, "ExpectationError"); }, "throws when called with too few args": function () { var expectation = this.expectation; expectation.withExactArgs(1, 2, 3); assert.exception(function () { expectation(1, 2); }, "ExpectationError"); }, "throws when called with wrong args": function () { var expectation = this.expectation; expectation.withExactArgs(1, 2, 3); assert.exception(function () { expectation(2, 2, 3); }, "ExpectationError"); }, "should not allow excessive args": function () { var expectation = this.expectation; expectation.withExactArgs(1, 2, 3); assert.exception(function () { expectation(1, 2, 3, 4); }, "ExpectationError"); }, "accepts call with no expected args": function () { this.expectation.withExactArgs(); this.expectation(); assert(this.expectation.met()); }, "does not allow excessive args with no expected args": function () { var expectation = this.expectation; expectation.withExactArgs(); assert.exception(function () { expectation(1, 2, 3); }, "ExpectationError"); } }, ".on": { "returns expectation for chaining": function () { assert.same(this.expectation.on({}), this.expectation); }, "allows calls on object": function () { this.expectation.on(this); this.expectation(); assert(this.expectation.met()); }, "throws if called on wrong object": function () { var expectation = this.expectation; expectation.on({}); assert.exception(function () { expectation(); }, "ExpectationError"); } }, ".verify": { "pass if met": function () { sinon.stub(sinon.expectation, "pass"); var expectation = this.expectation; expectation(); expectation.verify(); assert.equals(sinon.expectation.pass.callCount, 1); sinon.expectation.pass.restore(); }, "throws if not called enough times": function () { var expectation = this.expectation; assert.exception(function () { expectation.verify(); }, "ExpectationError"); }, "throws readable error": function () { var expectation = this.expectation; try { expectation.verify(); buster.referee.fail("Expected to throw"); } catch (e) { assert.equals(e.message, "Expected myMeth([...]) once (never called)"); } } } }, ".verify": { setUp: function () { this.method = function () {}; this.object = { method: this.method }; this.mock = sinon.mock.create(this.object); }, "restores mocks": function () { this.object.method(); this.object.method.call(this.thisValue); this.mock.verify(); assert.same(this.object.method, this.method); }, "passes verified mocks": function () { sinon.stub(sinon.expectation, "pass"); this.mock.expects("method").once(); this.object.method(); this.mock.verify(); assert.equals(sinon.expectation.pass.callCount, 1); sinon.expectation.pass.restore(); }, "restores if not met": function () { var mock = this.mock; mock.expects("method"); assert.exception(function () { mock.verify(); }, "ExpectationError"); assert.same(this.object.method, this.method); }, "includes all calls in error message": function () { var mock = this.mock; mock.expects("method").thrice(); mock.expects("method").once().withArgs(42); var message; try { mock.verify(); } catch (e) { message = e.message; } assert.equals( message, "Expected method([...]) thrice (never called)\nExpected method(42[, ...]) once (never called)" ); }, "includes exact expected arguments in error message": function () { var mock = this.mock; mock.expects("method").once().withExactArgs(42); var message; try { mock.verify(); } catch (e) { message = e.message; } assert.equals(message, "Expected method(42) once (never called)"); }, "includes received call count in error message": function () { var mock = this.mock; mock.expects("method").thrice().withExactArgs(42); this.object.method(42); var message; try { mock.verify(); } catch (e) { message = e.message; } assert.equals(message, "Expected method(42) thrice (called once)"); }, "includes unexpected calls in error message": function () { var mock = this.mock; mock.expects("method").thrice().withExactArgs(42); var message; try { this.object.method(); } catch (e) { message = e.message; } assert.equals(message, "Unexpected call: method()\n" + " Expected method(42) thrice (never called)"); }, "includes met expectations in error message": function () { var mock = this.mock; mock.expects("method").once().withArgs(1); mock.expects("method").thrice().withExactArgs(42); this.object.method(1); var message; try { this.object.method(); } catch (e) { message = e.message; } assert.equals(message, "Unexpected call: method()\n" + " Expectation met: method(1[, ...]) once\n" + " Expected method(42) thrice (never called)"); }, "includes met expectations in error message from verify": function () { var mock = this.mock; mock.expects("method").once().withArgs(1); mock.expects("method").thrice().withExactArgs(42); this.object.method(1); var message; try { mock.verify(); } catch (e) { message = e.message; } assert.equals(message, "Expected method(42) thrice (never called)\n" + "Expectation met: method(1[, ...]) once"); }, "reports min calls in error message": function () { var mock = this.mock; mock.expects("method").atLeast(1); var message; try { mock.verify(); } catch (e) { message = e.message; } assert.equals(message, "Expected method([...]) at least once (never called)"); }, "reports max calls in error message": function () { var mock = this.mock; mock.expects("method").atMost(2); var message; try { this.object.method(); this.object.method(); this.object.method(); } catch (e) { message = e.message; } assert.equals(message, "Unexpected call: method()\n" + " Expectation met: method([...]) at most twice"); }, "reports min calls in met expectation": function () { var mock = this.mock; mock.expects("method").atLeast(1); mock.expects("method").withArgs(2).once(); var message; try { this.object.method(); this.object.method(2); this.object.method(2); } catch (e) { message = e.message; } assert.equals(message, "Unexpected call: method(2)\n" + " Expectation met: method([...]) at least once\n" + " Expectation met: method(2[, ...]) once"); }, "reports max and min calls in error messages": function () { var mock = this.mock; mock.expects("method").atLeast(1).atMost(2); var message; try { mock.verify(); } catch (e) { message = e.message; } assert.equals(message, "Expected method([...]) at least once and at most twice " + "(never called)"); }, "does not call pass if no expectations": function () { var pass = sinon.stub(sinon.expectation, "pass"); var mock = this.mock; mock.expects("method").never(); delete mock.expectations; mock.verify(); refute(pass.called, "expectation.pass should not be called"); pass.restore(); } }, "mock object": { setUp: function () { this.method = function () {}; this.object = { method: this.method }; this.mock = sinon.mock.create(this.object); }, "mocks object method": function () { this.mock.expects("method"); assert.isFunction(this.object.method); refute.same(this.object.method, this.method); }, "reverts mocked method": function () { this.mock.expects("method"); this.object.method.restore(); assert.same(this.object.method, this.method); }, "reverts expectation": function () { this.mock.expects("method"); this.object.method.restore(); assert.same(this.object.method, this.method); }, "reverts mock": function () { this.mock.expects("method"); this.mock.restore(); assert.same(this.object.method, this.method); }, "verifies mock": function () { this.mock.expects("method"); this.object.method(); var mock = this.mock; refute.exception(function () { assert(mock.verify()); }); }, "verifies mock with unmet expectations": function () { this.mock.expects("method"); var mock = this.mock; assert.exception(function () { assert(mock.verify()); }, "ExpectationError"); } }, "mock method multiple times": { setUp: function () { this.thisValue = {}; this.method = function () {}; this.object = { method: this.method }; this.mock = sinon.mock.create(this.object); this.mock.expects("method"); this.mock.expects("method").on(this.thisValue); }, "queues expectations": function () { var object = this.object; refute.exception(function () { object.method(); }); }, "starts on next expectation when first is met": function () { var object = this.object; object.method(); assert.exception(function () { object.method(); }, "ExpectationError"); }, "fails on last expectation": function () { var object = this.object; object.method(); object.method.call(this.thisValue); assert.exception(function () { object.method(); }, "ExpectationError"); }, "allows mock calls in any order": function () { var object = { method: function () {} }; var mock = sinon.mock(object); mock.expects("method").once().withArgs(42); mock.expects("method").twice().withArgs("Yeah"); refute.exception(function () { object.method("Yeah"); }); refute.exception(function () { object.method(42); }); assert.exception(function () { object.method(1); }); refute.exception(function () { object.method("Yeah"); }); assert.exception(function () { object.method(42); }); } }, "mock function": { "returns mock method": function () { var mock = sinon.mock(); assert.isFunction(mock); assert.isFunction(mock.atLeast); assert.isFunction(mock.verify); }, "returns mock object": function () { var mock = sinon.mock({}); assert.isObject(mock); assert.isFunction(mock.expects); assert.isFunction(mock.verify); } }, ".yields": { "invokes only argument as callback": function () { var mock = sinon.mock().yields(); var spy = sinon.spy(); mock(spy); assert(spy.calledOnce); assert.equals(spy.args[0].length, 0); }, "throws understandable error if no callback is passed": function () { var mock = sinon.mock().yields(); try { mock(); throw new Error(); } catch (e) { assert.equals(e.message, "stub expected to yield, but no callback was passed."); } } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/sandbox-test.js000066400000000000000000000402411276775511300240420ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; var refute = buster.refute; var samsam = root.samsam || require("samsam"); var supportsAjax = typeof XMLHttpRequest !== "undefined" || typeof ActiveXObject !== "undefined"; var globalXHR = root.XMLHttpRequest; var globalAXO = root.ActiveXObject; if (!assert.stub) { require("./test-helper"); } buster.referee.add("fakeServerWithClock", { assert: function (obj, fakeServer) { return samsam.deepEqual(obj, fakeServer) && sinon.fakeServer.create.calledOn(sinon.fakeServerWithClock); }, assertMessage: "Expected object ${0} to be a fake server with clock" }); buster.testCase("sinon.sandbox", { "inherits collection": function () { assert(sinon.collection.isPrototypeOf(sinon.sandbox)); }, "creates sandboxes": function () { var sandbox = sinon.sandbox.create(); assert.isObject(sandbox); assert(sinon.sandbox.isPrototypeOf(sandbox)); }, "exposes match": function () { var sandbox = sinon.sandbox.create(); assert.same(sandbox.match, sinon.match); }, ".useFakeTimers": { setUp: function () { this.sandbox = sinon.create(sinon.sandbox); }, tearDown: function () { this.sandbox.restore(); }, "returns clock object": function () { var clock = this.sandbox.useFakeTimers(); assert.isObject(clock); assert.isFunction(clock.tick); }, "exposes clock property": function () { this.sandbox.useFakeTimers(); assert.isObject(this.sandbox.clock); assert.isFunction(this.sandbox.clock.tick); }, "uses restorable clock": function () { this.sandbox.useFakeTimers(); assert.isFunction(this.sandbox.clock.restore); }, "passes arguments to sinon.useFakeTimers": sinon.test(function () { var stub = this.stub(sinon, "useFakeTimers").returns({ restore: function () {} }); this.sandbox.useFakeTimers("Date", "setTimeout"); this.sandbox.useFakeTimers("setTimeout", "clearTimeout", "setInterval"); assert(sinon.useFakeTimers.calledWith("Date", "setTimeout")); assert(sinon.useFakeTimers.calledWith("setTimeout", "clearTimeout", "setInterval")); stub.restore(); }), "adds clock to fake collection": function () { this.sandbox.useFakeTimers(); this.sandbox.restore(); assert.same(setTimeout, sinon.timers.setTimeout); } }, // These were not run in browsers before, as we were only testing in node "//fake XHR/server": { // Causes problems in Chrome/Firefox // TODO: Figure out why // requiresSupportFor: { // "XHR/ActiveXObject": globalXHR || globalAXO // }, requiresSupportFor: { browser: typeof window !== "undefined" }, ".useFakeXMLHttpRequest": { setUp: function () { this.sandbox = sinon.sandbox.create(); }, tearDown: function () { this.sandbox.restore(); }, "calls sinon.useFakeXMLHttpRequest": function () { this.stub(sinon, "useFakeXMLHttpRequest").returns({ restore: function () {} }); this.sandbox.useFakeXMLHttpRequest(); assert(sinon.useFakeXMLHttpRequest.called); }, "adds fake xhr to fake collection": function () { this.sandbox.useFakeXMLHttpRequest(); this.sandbox.restore(); assert.same(global.XMLHttpRequest, globalXHR); assert.same(global.ActiveXObject, globalAXO); } }, ".useFakeServer": { setUp: function () { this.sandbox = sinon.create(sinon.sandbox); }, tearDown: function () { this.sandbox.restore(); }, "returns server": function () { var server = this.sandbox.useFakeServer(); assert.isObject(server); assert.isFunction(server.restore); }, "exposes server property": function () { var server = this.sandbox.useFakeServer(); assert.same(this.sandbox.server, server); }, "creates server": function () { var server = this.sandbox.useFakeServer(); assert(sinon.fakeServer.isPrototypeOf(server)); }, "creates server with cock": function () { this.sandbox.serverPrototype = sinon.fakeServerWithClock; var server = this.sandbox.useFakeServer(); assert(sinon.fakeServerWithClock.isPrototypeOf(server)); }, "adds server to fake collection": function () { this.sandbox.useFakeServer(); this.sandbox.restore(); assert.same(global.XMLHttpRequest, globalXHR); assert.same(global.ActiveXObject, globalAXO); } } }, ".inject": { setUp: function () { this.obj = {}; this.sandbox = sinon.sandbox.create(); }, tearDown: function () { this.sandbox.restore(); }, "injects spy, stub, mock": function () { this.sandbox.inject(this.obj); assert.isFunction(this.obj.spy); assert.isFunction(this.obj.stub); assert.isFunction(this.obj.mock); }, "does not define clock, server and requests objects": function () { this.sandbox.inject(this.obj); assert.isFalse("clock" in this.obj); assert.isFalse("server" in this.obj); assert.isFalse("requests" in this.obj); }, "defines clock when using fake time": function () { this.sandbox.useFakeTimers(); this.sandbox.inject(this.obj); assert.isFunction(this.obj.spy); assert.isFunction(this.obj.stub); assert.isFunction(this.obj.mock); assert.isObject(this.obj.clock); assert.isFalse("server" in this.obj); assert.isFalse("requests" in this.obj); }, "should return object": function () { var injected = this.sandbox.inject({}); assert.isObject(injected); assert.isFunction(injected.spy); }, "ajax options": { requiresSupportFor: { "ajax/browser": supportsAjax }, "defines server and requests when using fake time": function () { this.sandbox.useFakeServer(); this.sandbox.inject(this.obj); assert.isFunction(this.obj.spy); assert.isFunction(this.obj.stub); assert.isFunction(this.obj.mock); assert.isFalse("clock" in this.obj); assert.isObject(this.obj.server); assert.equals(this.obj.requests, []); }, "should define all possible fakes": function () { this.sandbox.useFakeServer(); this.sandbox.useFakeTimers(); this.sandbox.inject(this.obj); var spy = sinon.spy(); setTimeout(spy, 10); this.sandbox.clock.tick(10); var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"); //eslint-disable-line no-undef assert.isFunction(this.obj.spy); assert.isFunction(this.obj.stub); assert.isFunction(this.obj.mock); assert(spy.called); assert.isObject(this.obj.server); assert.equals(this.obj.requests, [xhr]); } } }, ".restore": { "throws when passed arguments": function () { var sandbox = sinon.sandbox.create(); assert.exception(function () { sandbox.restore("args"); }, { message: "sandbox.restore() does not take any parameters. Perhaps you meant stub.restore()" }); } }, "configurable sandbox": { setUp: function () { this.requests = []; this.fakeServer = { requests: this.requests }; this.clock = {}; sinon.stub(sinon, "useFakeTimers").returns(this.clock); if (sinon.fakeServer) { sinon.stub(sinon.fakeServer, "create").returns(this.fakeServer); } }, tearDown: function () { sinon.useFakeTimers.restore(); if (sinon.fakeServer) { sinon.fakeServer.create.restore(); } }, "yields stub, mock as arguments": function () { var sandbox = sinon.sandbox.create(sinon.getConfig({ injectIntoThis: false, properties: ["stub", "mock"] })); assert.equals(sandbox.args.length, 2); assert.stub(sandbox.args[0]()); assert.mock(sandbox.args[1]({})); sandbox.restore(); }, "yields spy, stub, mock as arguments": function () { var sandbox = sinon.sandbox.create(sinon.getConfig({ injectIntoThis: false, properties: ["spy", "stub", "mock"] })); assert.spy(sandbox.args[0]()); assert.stub(sandbox.args[1]()); assert.mock(sandbox.args[2]({})); sandbox.restore(); }, "does not yield server when not faking xhr": function () { var sandbox = sinon.sandbox.create(sinon.getConfig({ injectIntoThis: false, properties: ["server", "stub", "mock"], useFakeServer: false })); assert.equals(sandbox.args.length, 2); assert.stub(sandbox.args[0]()); assert.mock(sandbox.args[1]({})); sandbox.restore(); }, "does not inject properties if they are already present": function () { var server = function () {}; var clock = {}; var spy = false; var object = { server: server, clock: clock, spy: spy}; var sandbox = sinon.sandbox.create(sinon.getConfig({ properties: ["server", "clock", "spy"], injectInto: object })); assert.same(object.server, server); assert.same(object.clock, clock); assert.same(object.spy, spy); sandbox.restore(); }, "ajax options": { requiresSupportFor: { "ajax/browser": supportsAjax }, "yields server when faking xhr": function () { var sandbox = sinon.sandbox.create(sinon.getConfig({ injectIntoThis: false, properties: ["server", "stub", "mock"] })); assert.equals(sandbox.args.length, 3); assert.equals(sandbox.args[0], this.fakeServer); assert.stub(sandbox.args[1]()); assert.mock(sandbox.args[2]({})); sandbox.restore(); }, "uses serverWithClock when faking xhr": function () { var sandbox = sinon.sandbox.create(sinon.getConfig({ injectIntoThis: false, properties: ["server"], useFakeServer: sinon.fakeServerWithClock })); assert.fakeServerWithClock(sandbox.args[0], this.fakeServer); sandbox.restore(); }, "yields clock when faking timers": function () { var sandbox = sinon.sandbox.create(sinon.getConfig({ injectIntoThis: false, properties: ["server", "clock"] })); assert.same(sandbox.args[0], this.fakeServer); assert.same(sandbox.args[1], this.clock); sandbox.restore(); }, "injects properties into object": function () { var object = {}; var sandbox = sinon.sandbox.create(sinon.getConfig({ properties: ["server", "clock"], injectInto: object })); assert.equals(sandbox.args.length, 0); assert.equals(object.server, this.fakeServer); assert.equals(object.clock, this.clock); refute.defined(object.spy); refute.defined(object.stub); refute.defined(object.mock); refute.defined(object.requests); sandbox.restore(); }, "should inject server and clock when only enabling them": function () { var object = {}; var sandbox = sinon.sandbox.create(sinon.getConfig({ injectInto: object, useFakeTimers: true, useFakeServer: true })); assert.equals(sandbox.args.length, 0); assert.equals(object.server, this.fakeServer); assert.equals(object.clock, this.clock); assert.isFunction(object.spy); assert.isFunction(object.stub); assert.isFunction(object.mock); assert.isArray(object.requests); refute.defined(object.sandbox); sandbox.restore(); } }, "fakes specified timers": function () { var sandbox = sinon.sandbox.create(sinon.getConfig({ injectIntoThis: false, properties: ["clock"], useFakeTimers: ["Date", "setTimeout"] })); assert(sinon.useFakeTimers.calledWith("Date", "setTimeout")); sandbox.restore(); }, "injects sandbox": function () { var object = {}; var sandbox = sinon.sandbox.create(sinon.getConfig({ properties: ["sandbox", "spy"], injectInto: object })); assert.equals(sandbox.args.length, 0); assert.isFunction(object.spy); assert.isObject(object.sandbox); sandbox.restore(); }, "injects match": function () { var object = {}; var sandbox = sinon.sandbox.create(sinon.getConfig({ properties: ["match"], injectInto: object })); assert.same(object.match, sinon.match); sandbox.restore(); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/sinon-test.js000066400000000000000000000615461276775511300235450ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; var refute = buster.refute; buster.testCase("sinon", { ".wrapMethod": { setUp: function () { this.method = function () {}; this.getter = function () {}; this.setter = function () {}; this.object = {method: this.method}; Object.defineProperty(this.object, "property", { get: this.getter, set: this.setter, configurable: true }); }, "is function": function () { assert.isFunction(sinon.wrapMethod); }, "throws if first argument is not object": function () { assert.exception(function () { sinon.wrapMethod(); }, "TypeError"); }, "throws if object defines property but is not function": function () { this.object.prop = 42; var object = this.object; assert.exception(function () { sinon.wrapMethod(object, "prop", function () {}); }, "TypeError"); }, "throws if object does not define property": function () { var object = this.object; assert.exception(function () { sinon.wrapMethod(object, "prop", function () {}); }); try { sinon.wrapMethod(object, "prop", function () {}); throw new Error("Didn't throw"); } catch (e) { assert.match(e.message, /Attempted to wrap .* property .* as function/); } }, "throws if third argument is missing": function () { var object = this.object; assert.exception(function () { sinon.wrapMethod(object, "method"); }, "TypeError"); }, "throws if third argument is not a function or a property descriptor": function () { var object = this.object; assert.exception(function () { sinon.wrapMethod(object, "method", 1); }, "TypeError"); }, "replaces object method": function () { sinon.wrapMethod(this.object, "method", function () {}); refute.same(this.method, this.object.method); assert.isFunction(this.object.method); }, "replaces getter": function () { sinon.wrapMethod(this.object, "property", { get: function () {} }); refute.same(this.getter, Object.getOwnPropertyDescriptor(this.object, "property").get); assert.isFunction(Object.getOwnPropertyDescriptor(this.object, "property").get); }, "replaces setter": function () { sinon.wrapMethod(this.object, "property", { // eslint-disable-line accessor-pairs set: function () {} }); refute.same(this.setter, Object.getOwnPropertyDescriptor(this.object, "property").set); assert.isFunction(Object.getOwnPropertyDescriptor(this.object, "property").set); }, "throws if method is already wrapped": function () { sinon.wrapMethod(this.object, "method", function () {}); assert.exception(function () { sinon.wrapMethod(this.object, "method", function () {}); }, "TypeError"); }, "throws if property descriptor is already wrapped": function () { sinon.wrapMethod(this.object, "property", { get: function () {} }); assert.exception(function () { sinon.wrapMethod(this.object, "property", { get: function () {} }); }, "TypeError"); }, "throws if method is already a spy": function () { var object = { method: sinon.spy() }; assert.exception(function () { sinon.wrapMethod(object, "method", function () {}); }, "TypeError"); }, "originating stack traces": { requiresSupportFor: { "overriding Error and TypeError": (function () { return !(typeof navigator === "object" && /PhantomJS/.test(navigator.userAgent)); }()) }, setUp: function () { this.oldError = Error; this.oldTypeError = TypeError; var i = 0; /*eslint-disable no-native-reassign, no-undef*/ Error = TypeError = function () { this.stack = ":STACK" + ++i + ":"; }; /*eslint-enable no-native-reassign, no-undef*/ }, tearDown: function () { /*eslint-disable no-native-reassign, no-undef*/ Error = this.oldError; TypeError = this.oldTypeError; /*eslint-enable no-native-reassign, no-undef*/ }, "throws with stack trace showing original wrapMethod call": function () { var object = { method: function () {} }; sinon.wrapMethod(object, "method", function () { return "original"; }); try { sinon.wrapMethod(object, "method", function () {}); } catch (e) { assert.equals(e.stack, ":STACK2:\n--------------\n:STACK1:"); } } }, "in browser": { requiresSupportFor: { "window object": typeof window !== "undefined" }, "does not throw if object is window object": function () { window.sinonTestMethod = function () {}; try { refute.exception(function () { sinon.wrapMethod(window, "sinonTestMethod", function () {}); }); } finally { // IE 8 does not support delete on global properties. window.sinonTestMethod = undefined; } } }, "mirrors function properties": function () { var object = { method: function () {} }; object.method.prop = 42; sinon.wrapMethod(object, "method", function () {}); assert.equals(object.method.prop, 42); }, "does not mirror and overwrite existing properties": function () { var object = { method: function () {} }; object.method.called = 42; sinon.stub(object, "method"); assert.isFalse(object.method.called); } }, "wrapped method": { setUp: function () { this.method = function () {}; this.object = { method: this.method }; }, "defines restore method": function () { sinon.wrapMethod(this.object, "method", function () {}); assert.isFunction(this.object.method.restore); }, "returns wrapper": function () { var wrapper = sinon.wrapMethod(this.object, "method", function () {}); assert.same(this.object.method, wrapper); }, "restore brings back original method": function () { sinon.wrapMethod(this.object, "method", function () {}); this.object.method.restore(); assert.same(this.object.method, this.method); } }, "wrapped prototype method": { setUp: function () { this.type = function () {}; this.type.prototype.method = function () {}; this.object = new this.type(); //eslint-disable-line new-cap }, "wrap adds owned property": function () { var wrapper = sinon.wrapMethod(this.object, "method", function () {}); assert.same(this.object.method, wrapper); assert(this.object.hasOwnProperty("method")); }, "restore removes owned property": function () { sinon.wrapMethod(this.object, "method", function () {}); this.object.method.restore(); assert.same(this.object.method, this.type.prototype.method); assert.isFalse(this.object.hasOwnProperty("method")); } }, ".deepEqual": { "passes null": function () { assert(sinon.deepEqual(null, null)); }, "fails null and object": function () { assert.isFalse(sinon.deepEqual(null, {})); }, "fails object and null": function () { assert.isFalse(sinon.deepEqual({}, null)); }, "fails error and object": function () { assert.isFalse(sinon.deepEqual(new Error(), {})); }, "fails object and error": function () { assert.isFalse(sinon.deepEqual({}, new Error())); }, "fails regexp and object": function () { assert.isFalse(sinon.deepEqual(/.*/, {})); }, "fails object and regexp": function () { assert.isFalse(sinon.deepEqual({}, /.*/)); }, "passes primitives": function () { assert(sinon.deepEqual(1, 1)); }, "passes same object": function () { var object = {}; assert(sinon.deepEqual(object, object)); }, "passes same function": function () { var func = function () {}; assert(sinon.deepEqual(func, func)); }, "passes same array": function () { var arr = []; assert(sinon.deepEqual(arr, arr)); }, "passes same regexp": function () { var regexp = /foo/; assert(sinon.deepEqual(regexp, regexp)); }, "passes equal arrays": function () { var arr1 = [1, 2, 3, "hey", "there"]; var arr2 = [1, 2, 3, "hey", "there"]; assert(sinon.deepEqual(arr1, arr2)); }, "passes equal arrays with custom properties": function () { var arr1 = [1, 2, 3, "hey", "there"]; var arr2 = [1, 2, 3, "hey", "there"]; arr1.foo = "bar"; arr2.foo = "bar"; assert(sinon.deepEqual(arr1, arr2)); }, "fails arrays with unequal custom properties": function () { var arr1 = [1, 2, 3, "hey", "there"]; var arr2 = [1, 2, 3, "hey", "there"]; arr1.foo = "bar"; arr2.foo = "not bar"; assert.isFalse(sinon.deepEqual(arr1, arr2)); }, "passes equal regexps": function () { var regexp1 = /foo/; var regexp2 = /foo/; assert(sinon.deepEqual(regexp1, regexp2)); }, "fails unequal regexps": function () { var regexp1 = /foo/; var regexp2 = /bar/; assert.isFalse(sinon.deepEqual(regexp1, regexp2)); }, "passes equal regexps with same ignoreCase flags": function () { var regexp1 = /foo/i; var regexp2 = /foo/i; assert(sinon.deepEqual(regexp1, regexp2)); }, "fails unequal regexps with different ignoreCase flags": function () { var regexp1 = /foo/i; var regexp2 = /foo/; assert.isFalse(sinon.deepEqual(regexp1, regexp2)); }, "passes equal regexps with same multiline flags": function () { var regexp1 = /foo/m; var regexp2 = /foo/m; assert(sinon.deepEqual(regexp1, regexp2)); }, "fails unequal regexps with different multiline flags": function () { var regexp1 = /foo/m; var regexp2 = /foo/; assert.isFalse(sinon.deepEqual(regexp1, regexp2)); }, "passes equal regexps with same global flags": function () { var regexp1 = /foo/g; var regexp2 = /foo/g; assert(sinon.deepEqual(regexp1, regexp2)); }, "fails unequal regexps with different global flags": function () { var regexp1 = /foo/g; var regexp2 = /foo/; assert.isFalse(sinon.deepEqual(regexp1, regexp2)); }, "passes equal regexps with multiple flags": function () { var regexp1 = /bar/im; var regexp2 = /bar/im; assert(sinon.deepEqual(regexp1, regexp2)); }, "fails unequal regexps with multiple flags": function () { var regexp1 = /bar/im; var regexp2 = /bar/ig; assert.isFalse(sinon.deepEqual(regexp1, regexp2)); }, "passes NaN and NaN": function () { assert(sinon.deepEqual(NaN, NaN)); }, "passes equal objects": function () { var obj1 = { a: 1, b: 2, c: 3, d: "hey", e: "there" }; var obj2 = { b: 2, c: 3, a: 1, d: "hey", e: "there" }; assert(sinon.deepEqual(obj1, obj2)); }, "fails unequal objects with undefined properties with different names": function () { var obj1 = {a: 1, b: 2, c: 3}; var obj2 = {a: 1, b: 2, foo: undefined}; assert.isFalse(sinon.deepEqual(obj1, obj2)); }, "fails unequal objects with undefined properties with different names (different arg order)": function () { var obj1 = {a: 1, b: 2, foo: undefined}; var obj2 = {a: 1, b: 2, c: 3}; assert.isFalse(sinon.deepEqual(obj1, obj2)); }, "passes equal dates": function () { var date1 = new Date(2012, 3, 5); var date2 = new Date(2012, 3, 5); assert(sinon.deepEqual(date1, date2)); }, "fails different dates": function () { var date1 = new Date(2012, 3, 5); var date2 = new Date(2013, 3, 5); assert.isFalse(sinon.deepEqual(date1, date2)); }, "in browsers": { requiresSupportFor: { "document object": typeof document !== "undefined" }, "passes same DOM elements": function () { var element = document.createElement("div"); assert(sinon.deepEqual(element, element)); }, "fails different DOM elements": function () { var element = document.createElement("div"); var el = document.createElement("div"); assert.isFalse(sinon.deepEqual(element, el)); }, "does not modify DOM elements when comparing them": function () { var el = document.createElement("div"); document.body.appendChild(el); sinon.deepEqual(el, {}); assert.same(el.parentNode, document.body); assert.equals(el.childNodes.length, 0); } }, "passes deep objects": function () { var func = function () {}; var obj1 = { a: 1, b: 2, c: 3, d: "hey", e: "there", f: func, g: { a1: [1, 2, "3", { prop: [func, "b"] }] } }; var obj2 = { a: 1, b: 2, c: 3, d: "hey", e: "there", f: func, g: { a1: [1, 2, "3", { prop: [func, "b"] }] } }; assert(sinon.deepEqual(obj1, obj2)); }, "passes object without prototype compared to equal object with prototype": function () { var obj1 = Object.create(null); obj1.a = 1; obj1.b = 2; obj1.c = "hey"; var obj2 = { a: 1, b: 2, c: "hey" }; assert(sinon.deepEqual(obj1, obj2)); }, "passes object with prototype compared to equal object without prototype": function () { var obj1 = { a: 1, b: 2, c: "hey" }; var obj2 = Object.create(null); obj2.a = 1; obj2.b = 2; obj2.c = "hey"; assert(sinon.deepEqual(obj1, obj2)); }, "passes equal objects without prototypes": function () { var obj1 = Object.create(null); obj1.a = 1; obj1.b = 2; obj1.c = "hey"; var obj2 = Object.create(null); obj2.a = 1; obj2.b = 2; obj2.c = "hey"; assert(sinon.deepEqual(obj1, obj2)); }, "passes equal objects that override hasOwnProperty": function () { var obj1 = { a: 1, b: 2, c: "hey", hasOwnProperty: "silly" }; var obj2 = { a: 1, b: 2, c: "hey", hasOwnProperty: "silly" }; assert(sinon.deepEqual(obj1, obj2)); } }, ".extend": { "copies all properties": function () { var object1 = { prop1: null, prop2: false }; var object2 = { prop3: "hey", prop4: 4 }; var result = sinon.extend({}, object1, object2); var expected = { prop1: null, prop2: false, prop3: "hey", prop4: 4 }; assert.equals(result, expected); } }, "Function.prototype.toString": { "returns function's displayName property": function () { var fn = function () {}; fn.displayName = "Larry"; assert.equals(sinon.functionToString.call(fn), "Larry"); }, "guesses name from last call's this object": function () { var obj = {}; obj.doStuff = sinon.spy(); obj.doStuff.call({}); obj.doStuff(); assert.equals(sinon.functionToString.call(obj.doStuff), "doStuff"); }, "guesses name from any call where property can be located": function () { var obj = {}; var otherObj = { id: 42 }; obj.doStuff = sinon.spy(); obj.doStuff.call({}); obj.doStuff(); obj.doStuff.call(otherObj); assert.equals(sinon.functionToString.call(obj.doStuff), "doStuff"); } }, ".getConfig": { "gets copy of default config": function () { var config = sinon.getConfig(); refute.same(config, sinon.defaultConfig); assert.equals(config.injectIntoThis, sinon.defaultConfig.injectIntoThis); assert.equals(config.injectInto, sinon.defaultConfig.injectInto); assert.equals(config.properties, sinon.defaultConfig.properties); assert.equals(config.useFakeTimers, sinon.defaultConfig.useFakeTimers); assert.equals(config.useFakeServer, sinon.defaultConfig.useFakeServer); }, "should override specified properties": function () { var config = sinon.getConfig({ properties: ["stub", "mock"], useFakeServer: false }); refute.same(config, sinon.defaultConfig); assert.equals(config.injectIntoThis, sinon.defaultConfig.injectIntoThis); assert.equals(config.injectInto, sinon.defaultConfig.injectInto); assert.equals(config.properties, ["stub", "mock"]); assert.equals(config.useFakeTimers, sinon.defaultConfig.useFakeTimers); assert.isFalse(config.useFakeServer); } }, ".log": { "does nothing gracefully": function () { refute.exception(function () { sinon.log("Oh, hiya"); }); } }, ".createStubInstance": { "stubs existing methods": function () { var Class = function () {}; Class.prototype.method = function () {}; var stub = sinon.createStubInstance(Class); stub.method.returns(3); assert.equals(3, stub.method()); }, "doesn't stub fake methods": function () { var Class = function () {}; var stub = sinon.createStubInstance(Class); assert.exception(function () { stub.method.returns(3); }); }, "doesn't call the constructor": function () { var Class = function (a, b) { var c = a + b; throw c; }; Class.prototype.method = function () {}; var stub = sinon.createStubInstance(Class); refute.exception(function () { stub.method(3); }); }, "retains non function values": function () { var TYPE = "some-value"; var Class = function () {}; Class.prototype.type = TYPE; var stub = sinon.createStubInstance(Class); assert.equals(TYPE, stub.type); }, "has no side effects on the prototype": function () { var proto = { method: function () { throw "error"; } }; var Class = function () {}; Class.prototype = proto; var stub = sinon.createStubInstance(Class); refute.exception(stub.method); assert.exception(proto.method); }, "throws exception for non function params": function () { var types = [{}, 3, "hi!"]; for (var i = 0; i < types.length; i++) { // yes, it's silly to create functions in a loop, it's also a test assert.exception(function () { // eslint-disable-line no-loop-func sinon.createStubInstance(types[i]); }); } } }, ".restore": { "restores all methods of supplied object": function () { var methodA = function () {}; var methodB = function () {}; var obj = { methodA: methodA, methodB: methodB }; sinon.stub(obj); sinon.restore(obj); assert.same(obj.methodA, methodA); assert.same(obj.methodB, methodB); }, "only restores restorable methods": function () { var stubbedMethod = function () {}; var vanillaMethod = function () {}; var obj = { stubbedMethod: stubbedMethod, vanillaMethod: vanillaMethod }; sinon.stub(obj, "stubbedMethod"); sinon.restore(obj); assert.same(obj.stubbedMethod, stubbedMethod); }, "restores a single stubbed method": function () { var method = function () {}; var obj = { method: method }; sinon.stub(obj); sinon.restore(obj.method); assert.same(obj.method, method); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/spy-test.js000066400000000000000000002066571276775511300232360ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; var refute = buster.refute; function spyCalledTests(method) { return { setUp: function () { this.spy = sinon.spy.create(); }, "returns false if spy was not called": function () { assert.isFalse(this.spy[method](1, 2, 3)); }, "returns true if spy was called with args": function () { this.spy(1, 2, 3); assert(this.spy[method](1, 2, 3)); }, "returns true if called with args at least once": function () { this.spy(1, 3, 3); this.spy(1, 2, 3); this.spy(3, 2, 3); assert(this.spy[method](1, 2, 3)); }, "returns false if not called with args": function () { this.spy(1, 3, 3); this.spy(2); this.spy(); assert.isFalse(this.spy[method](1, 2, 3)); }, "returns false if not called with undefined": function () { this.spy(); assert.isFalse(this.spy[method](undefined)); }, "returns true for partial match": function () { this.spy(1, 3, 3); this.spy(2); this.spy(); assert(this.spy[method](1, 3)); }, "matchs all arguments individually, not as array": function () { this.spy([1, 2, 3]); assert.isFalse(this.spy[method](1, 2, 3)); }, "uses matcher": function () { this.spy("abc"); assert(this.spy[method](sinon.match.typeOf("string"))); }, "uses matcher in object": function () { this.spy({ some: "abc" }); assert(this.spy[method]({ some: sinon.match.typeOf("string") })); } }; } function spyAlwaysCalledTests(method) { return { setUp: function () { this.spy = sinon.spy.create(); }, "returns false if spy was not called": function () { assert.isFalse(this.spy[method](1, 2, 3)); }, "returns true if spy was called with args": function () { this.spy(1, 2, 3); assert(this.spy[method](1, 2, 3)); }, "returns false if called with args only once": function () { this.spy(1, 3, 3); this.spy(1, 2, 3); this.spy(3, 2, 3); assert.isFalse(this.spy[method](1, 2, 3)); }, "returns false if not called with args": function () { this.spy(1, 3, 3); this.spy(2); this.spy(); assert.isFalse(this.spy[method](1, 2, 3)); }, "returns true for partial match": function () { this.spy(1, 3, 3); assert(this.spy[method](1, 3)); }, "returns true for partial match on many calls": function () { this.spy(1, 3, 3); this.spy(1, 3); this.spy(1, 3, 4, 5); this.spy(1, 3, 1); assert(this.spy[method](1, 3)); }, "matchs all arguments individually, not as array": function () { this.spy([1, 2, 3]); assert.isFalse(this.spy[method](1, 2, 3)); } }; } function spyNeverCalledTests(method) { return { setUp: function () { this.spy = sinon.spy.create(); }, "returns true if spy was not called": function () { assert(this.spy[method](1, 2, 3)); }, "returns false if spy was called with args": function () { this.spy(1, 2, 3); assert.isFalse(this.spy[method](1, 2, 3)); }, "returns false if called with args at least once": function () { this.spy(1, 3, 3); this.spy(1, 2, 3); this.spy(3, 2, 3); assert.isFalse(this.spy[method](1, 2, 3)); }, "returns true if not called with args": function () { this.spy(1, 3, 3); this.spy(2); this.spy(); assert(this.spy[method](1, 2, 3)); }, "returns false for partial match": function () { this.spy(1, 3, 3); this.spy(2); this.spy(); assert.isFalse(this.spy[method](1, 3)); }, "matchs all arguments individually, not as array": function () { this.spy([1, 2, 3]); assert(this.spy[method](1, 2, 3)); } }; } buster.testCase("sinon.spy", { "does not throw if called without function": function () { refute.exception(function () { sinon.spy.create(); }); }, "does not throw when calling anonymous spy": function () { var spy = sinon.spy.create(); refute.exception(function () { spy(); }); assert(spy.called); }, "returns spy function": function () { var func = function () {}; var spy = sinon.spy.create(func); assert.isFunction(spy); refute.same(func, spy); }, "mirrors custom properties on function": function () { var func = function () {}; func.myProp = 42; var spy = sinon.spy.create(func); assert.equals(spy.myProp, func.myProp); }, "does not define create method": function () { var spy = sinon.spy.create(); refute.defined(spy.create); }, "does not overwrite original create property": function () { var func = function () {}; var object = func.create = {}; var spy = sinon.spy.create(func); assert.same(spy.create, object); }, "sets up logging arrays": function () { var spy = sinon.spy.create(); assert.isArray(spy.args); assert.isArray(spy.returnValues); assert.isArray(spy.thisValues); assert.isArray(spy.exceptions); }, ".named": { "sets displayName": function () { var spy = sinon.spy(); var retval = spy.named("beep"); assert.equals(spy.displayName, "beep"); assert.same(spy, retval); } }, call: { "calls underlying function": function () { var called = false; var spy = sinon.spy.create(function () { called = true; }); spy(); assert(called); }, "passs arguments to function": function () { var actualArgs; var func = function (a, b, c, d) { actualArgs = [a, b, c, d]; }; var args = [1, {}, [], ""]; var spy = sinon.spy.create(func); spy(args[0], args[1], args[2], args[3]); assert.equals(actualArgs, args); }, "maintains this binding": function () { var actualThis; var func = function () { actualThis = this; }; var object = {}; var spy = sinon.spy.create(func); spy.call(object); assert.same(actualThis, object); }, "returns function's return value": function () { var object = {}; var func = function () { return object; }; var spy = sinon.spy.create(func); var actualReturn = spy(); assert.same(actualReturn, object); }, "throws if function throws": function () { var err = new Error(); var spy = sinon.spy.create(function () { throw err; }); try { spy(); buster.referee.fail("Expected spy to throw exception"); } catch (e) { assert.same(e, err); } }, "retains function length 0": function () { var spy = sinon.spy.create(function () {}); assert.equals(spy.length, 0); }, "retains function length 1": function () { var spy = sinon.spy.create(function (a) {}); // eslint-disable-line no-unused-vars assert.equals(spy.length, 1); }, "retains function length 2": function () { var spy = sinon.spy.create(function (a, b) {}); // eslint-disable-line no-unused-vars assert.equals(spy.length, 2); }, "retains function length 3": function () { var spy = sinon.spy.create(function (a, b, c) {}); // eslint-disable-line no-unused-vars assert.equals(spy.length, 3); }, "retains function length 4": function () { var spy = sinon.spy.create(function (a, b, c, d) {}); // eslint-disable-line no-unused-vars assert.equals(spy.length, 4); }, "retains function length 12": function () { var func12Args = function (a, b, c, d, e, f, g, h, i, j, k, l) {}; // eslint-disable-line no-unused-vars var spy = sinon.spy.create(func12Args); assert.equals(spy.length, 12); } }, ".called": { setUp: function () { this.spy = sinon.spy.create(); }, "is false prior to calling the spy": function () { assert.isFalse(this.spy.called); }, "is true after calling the spy once": function () { this.spy(); assert(this.spy.called); }, "is true after calling the spy twice": function () { this.spy(); this.spy(); assert(this.spy.called); } }, ".notCalled": { setUp: function () { this.spy = sinon.spy.create(); }, "is true prior to calling the spy": function () { assert.isTrue(this.spy.notCalled); }, "is false after calling the spy once": function () { this.spy(); assert.isFalse(this.spy.notCalled); } }, ".calledOnce": { setUp: function () { this.spy = sinon.spy.create(); }, "is false prior to calling the spy": function () { assert.isFalse(this.spy.calledOnce); }, "is true after calling the spy once": function () { this.spy(); assert(this.spy.calledOnce); }, "is false after calling the spy twice": function () { this.spy(); this.spy(); assert.isFalse(this.spy.calledOnce); } }, ".calledTwice": { setUp: function () { this.spy = sinon.spy.create(); }, "is false prior to calling the spy": function () { assert.isFalse(this.spy.calledTwice); }, "is false after calling the spy once": function () { this.spy(); assert.isFalse(this.spy.calledTwice); }, "is true after calling the spy twice": function () { this.spy(); this.spy(); assert(this.spy.calledTwice); }, "is false after calling the spy thrice": function () { this.spy(); this.spy(); this.spy(); assert.isFalse(this.spy.calledTwice); } }, ".calledThrice": { setUp: function () { this.spy = sinon.spy.create(); }, "is false prior to calling the spy": function () { assert.isFalse(this.spy.calledThrice); }, "is false after calling the spy twice": function () { this.spy(); this.spy(); assert.isFalse(this.spy.calledThrice); }, "is true after calling the spy thrice": function () { this.spy(); this.spy(); this.spy(); assert(this.spy.calledThrice); }, "is false after calling the spy four times": function () { this.spy(); this.spy(); this.spy(); this.spy(); assert.isFalse(this.spy.calledThrice); } }, ".callCount": { setUp: function () { this.spy = sinon.spy.create(); }, "reports 0 calls": function () { assert.equals(this.spy.callCount, 0); }, "records one call": function () { this.spy(); assert.equals(this.spy.callCount, 1); }, "records two calls": function () { this.spy(); this.spy(); assert.equals(this.spy.callCount, 2); }, "increases call count for each call": function () { this.spy(); this.spy(); assert.equals(this.spy.callCount, 2); this.spy(); assert.equals(this.spy.callCount, 3); } }, ".calledOn": { setUp: function () { this.spy = sinon.spy.create(); }, "is false if spy wasn't called": function () { assert.isFalse(this.spy.calledOn({})); }, "is true if called with thisValue": function () { var object = {}; this.spy.call(object); assert(this.spy.calledOn(object)); }, "in browser": { requiresSupportFor: { browser: typeof window !== "undefined" }, "is true if called on object at least once": function () { var object = {}; this.spy(); this.spy.call({}); this.spy.call(object); this.spy.call(window); assert(this.spy.calledOn(object)); } }, "returns false if not called on object": function () { var object = {}; this.spy.call(object); this.spy(); assert.isFalse(this.spy.calledOn({})); }, "is true if called with matcher that returns true": function () { var matcher = sinon.match(function () { return true; }); this.spy(); assert(this.spy.calledOn(matcher)); }, "is false if called with matcher that returns false": function () { var matcher = sinon.match(function () { return false; }); this.spy(); assert.isFalse(this.spy.calledOn(matcher)); }, "invokes matcher.test with given object": function () { var expected = {}; var actual; this.spy.call(expected); this.spy.calledOn(sinon.match(function (value) { actual = value; })); assert.same(actual, expected); } }, ".alwaysCalledOn": { setUp: function () { this.spy = sinon.spy.create(); }, "is false prior to calling the spy": function () { assert.isFalse(this.spy.alwaysCalledOn({})); }, "is true if called with thisValue once": function () { var object = {}; this.spy.call(object); assert(this.spy.alwaysCalledOn(object)); }, "is true if called with thisValue many times": function () { var object = {}; this.spy.call(object); this.spy.call(object); this.spy.call(object); this.spy.call(object); assert(this.spy.alwaysCalledOn(object)); }, "is false if called with another object atleast once": function () { var object = {}; this.spy.call(object); this.spy.call(object); this.spy.call(object); this.spy(); this.spy.call(object); assert.isFalse(this.spy.alwaysCalledOn(object)); }, "is false if never called with expected object": function () { var object = {}; this.spy(); this.spy(); this.spy(); assert.isFalse(this.spy.alwaysCalledOn(object)); } }, ".calledWithNew": { setUp: function () { this.spy = sinon.spy.create(); }, "is false if spy wasn't called": function () { assert.isFalse(this.spy.calledWithNew()); }, "is true if called with new": function () { var result = new this.spy(); // eslint-disable-line no-unused-vars, new-cap assert(this.spy.calledWithNew()); }, "is true if called with new on custom constructor": function () { function MyThing() {} MyThing.prototype = {}; var ns = { MyThing: MyThing }; sinon.spy(ns, "MyThing"); var result = new ns.MyThing(); // eslint-disable-line no-unused-vars assert(ns.MyThing.calledWithNew()); }, "is false if called as function": function () { this.spy(); assert.isFalse(this.spy.calledWithNew()); }, "in browser": { requiresSupportFor: { browser: typeof window !== "undefined" }, "is true if called with new at least once": function () { var object = {}; this.spy(); var a = new this.spy(); // eslint-disable-line no-unused-vars, new-cap this.spy(object); this.spy(window); assert(this.spy.calledWithNew()); } }, "is true newed constructor returns object": function () { function MyThing() { return {}; } var object = { MyThing: MyThing }; sinon.spy(object, "MyThing"); var result = new object.MyThing(); // eslint-disable-line no-unused-vars assert(object.MyThing.calledWithNew()); }, "spied native function": { requiresSupportFor: { applyableNatives: function () { try { console.log.apply({}, []); // eslint-disable-line no-console return true; } catch (e) { return false; } } }, "is false when called on spied native function": function () { var log = { info: console.log }; // eslint-disable-line no-console sinon.spy(log, "info"); log.info("test"); assert.isFalse(log.info.calledWithNew()); } } }, ".alwaysCalledWithNew": { setUp: function () { this.spy = sinon.spy.create(); }, "is false if spy wasn't called": function () { assert.isFalse(this.spy.alwaysCalledWithNew()); }, "is true if always called with new": function () { /*eslint-disable no-unused-vars, new-cap*/ var result = new this.spy(); var result2 = new this.spy(); var result3 = new this.spy(); /*eslint-enable no-unused-vars, new-cap*/ assert(this.spy.alwaysCalledWithNew()); }, "is false if called as function once": function () { /*eslint-disable no-unused-vars, new-cap*/ var result = new this.spy(); var result2 = new this.spy(); /*eslint-enable no-unused-vars, new-cap*/ this.spy(); assert.isFalse(this.spy.alwaysCalledWithNew()); } }, ".thisValues": { setUp: function () { this.spy = sinon.spy.create(); }, "contains one object": function () { var object = {}; this.spy.call(object); assert.equals(this.spy.thisValues, [object]); }, "stacks up objects": function () { function MyConstructor() {} var objects = [{}, [], new MyConstructor(), { id: 243 }]; this.spy(); this.spy.call(objects[0]); this.spy.call(objects[1]); this.spy.call(objects[2]); this.spy.call(objects[3]); assert.equals(this.spy.thisValues, [this].concat(objects)); } }, ".calledWith": spyCalledTests("calledWith"), ".calledWithMatch": spyCalledTests("calledWithMatch"), ".calledWithMatchSpecial": { setUp: function () { this.spy = sinon.spy.create(); }, "checks substring match": function () { this.spy("I like it"); assert(this.spy.calledWithMatch("like")); assert.isFalse(this.spy.calledWithMatch("nope")); }, "checks for regexp match": function () { this.spy("I like it"); assert(this.spy.calledWithMatch(/[a-z ]+/i)); assert.isFalse(this.spy.calledWithMatch(/[0-9]+/)); }, "checks for partial object match": function () { this.spy({ foo: "foo", bar: "bar" }); assert(this.spy.calledWithMatch({ bar: "bar" })); assert.isFalse(this.spy.calledWithMatch({ same: "same" })); } }, ".alwaysCalledWith": spyAlwaysCalledTests("alwaysCalledWith"), ".alwaysCalledWithMatch": spyAlwaysCalledTests("alwaysCalledWithMatch"), ".alwaysCalledWithMatchSpecial": { setUp: function () { this.spy = sinon.spy.create(); }, "checks true": function () { this.spy(true); assert(this.spy.alwaysCalledWithMatch(true)); assert.isFalse(this.spy.alwaysCalledWithMatch(false)); }, "checks false": function () { this.spy(false); assert(this.spy.alwaysCalledWithMatch(false)); assert.isFalse(this.spy.alwaysCalledWithMatch(true)); }, "checks substring match": function () { this.spy("test case"); this.spy("some test"); this.spy("all tests"); assert(this.spy.alwaysCalledWithMatch("test")); assert.isFalse(this.spy.alwaysCalledWithMatch("case")); }, "checks regexp match": function () { this.spy("1"); this.spy("2"); this.spy("3"); assert(this.spy.alwaysCalledWithMatch(/[123]/)); assert.isFalse(this.spy.alwaysCalledWithMatch(/[12]/)); }, "checks partial object match": function () { this.spy({ a: "a", b: "b" }); this.spy({ c: "c", b: "b" }); this.spy({ b: "b", d: "d" }); assert(this.spy.alwaysCalledWithMatch({ b: "b" })); assert.isFalse(this.spy.alwaysCalledWithMatch({ a: "a" })); } }, ".neverCalledWith": spyNeverCalledTests("neverCalledWith"), ".neverCalledWithMatch": spyNeverCalledTests("neverCalledWithMatch"), ".neverCalledWithMatchSpecial": { setUp: function () { this.spy = sinon.spy.create(); }, "checks substring match": function () { this.spy("a test", "b test"); assert(this.spy.neverCalledWithMatch("a", "a")); assert(this.spy.neverCalledWithMatch("b", "b")); assert(this.spy.neverCalledWithMatch("b", "a")); assert.isFalse(this.spy.neverCalledWithMatch("a", "b")); }, "checks regexp match": function () { this.spy("a test", "b test"); assert(this.spy.neverCalledWithMatch(/a/, /a/)); assert(this.spy.neverCalledWithMatch(/b/, /b/)); assert(this.spy.neverCalledWithMatch(/b/, /a/)); assert.isFalse(this.spy.neverCalledWithMatch(/a/, /b/)); }, "checks partial object match": function () { this.spy({ a: "test", b: "test" }); assert(this.spy.neverCalledWithMatch({ a: "nope" })); assert(this.spy.neverCalledWithMatch({ c: "test" })); assert.isFalse(this.spy.neverCalledWithMatch({ b: "test" })); } }, ".args": { setUp: function () { this.spy = sinon.spy.create(); }, "contains real arrays": function () { this.spy(); assert.isArray(this.spy.args[0]); }, "contains empty array when no arguments": function () { this.spy(); assert.equals(this.spy.args, [[]]); }, "contains array with first call's arguments": function () { this.spy(1, 2, 3); assert.equals(this.spy.args, [[1, 2, 3]]); }, "stacks up arguments in nested array": function () { var objects = [{}, [], { id: 324 }]; this.spy(1, objects[0], 3); this.spy(1, 2, objects[1]); this.spy(objects[2], 2, 3); assert.equals(this.spy.args, [ [1, objects[0], 3], [1, 2, objects[1]], [objects[2], 2, 3] ]); } }, ".calledWithExactly": { setUp: function () { this.spy = sinon.spy.create(); }, "returns false for partial match": function () { this.spy(1, 2, 3); assert.isFalse(this.spy.calledWithExactly(1, 2)); }, "returns false for missing arguments": function () { this.spy(1, 2, 3); assert.isFalse(this.spy.calledWithExactly(1, 2, 3, 4)); }, "returns true for exact match": function () { this.spy(1, 2, 3); assert(this.spy.calledWithExactly(1, 2, 3)); }, "matchs by strict comparison": function () { this.spy({}, []); assert.isFalse(this.spy.calledWithExactly({}, [], null)); }, "returns true for one exact match": function () { var object = {}; var array = []; this.spy({}, []); this.spy(object, []); this.spy(object, array); assert(this.spy.calledWithExactly(object, array)); }, "returns true when all properties of an object argument match": function () { this.spy({a: 1, b: 2, c: 3}); assert(this.spy.calledWithExactly({a: 1, b: 2, c: 3})); }, "returns false when a property of an object argument is set to undefined": function () { this.spy({a: 1, b: 2, c: 3}); assert.isFalse(this.spy.calledWithExactly({a: 1, b: 2, c: undefined})); }, "returns false when a property of an object argument is set to a different value": function () { this.spy({a: 1, b: 2, c: 3}); assert.isFalse(this.spy.calledWithExactly({a: 1, b: 2, c: "blah"})); }, "returns false when an object argument has a different property/value pair": function () { this.spy({a: 1, b: 2, c: 3}); assert.isFalse(this.spy.calledWithExactly({a: 1, b: 2, foo: "blah"})); }, "returns false when property of Object argument is set to undefined and has a different name": function () { this.spy({a: 1, b: 2, c: 3}); assert.isFalse(this.spy.calledWithExactly({a: 1, b: 2, foo: undefined})); }, "returns false when any properties of an object argument aren't present": function () { this.spy({a: 1, b: 2, c: 3}); assert.isFalse(this.spy.calledWithExactly({a: 1, b: 2})); }, "returns false when an object argument has extra properties": function () { this.spy({a: 1, b: 2, c: 3}); assert.isFalse(this.spy.calledWithExactly({a: 1, b: 2, c: 3, d: 4})); } }, ".alwaysCalledWithExactly": { setUp: function () { this.spy = sinon.spy.create(); }, "returns false for partial match": function () { this.spy(1, 2, 3); assert.isFalse(this.spy.alwaysCalledWithExactly(1, 2)); }, "returns false for missing arguments": function () { this.spy(1, 2, 3); assert.isFalse(this.spy.alwaysCalledWithExactly(1, 2, 3, 4)); }, "returns true for exact match": function () { this.spy(1, 2, 3); assert(this.spy.alwaysCalledWithExactly(1, 2, 3)); }, "returns false for excess arguments": function () { this.spy({}, []); assert.isFalse(this.spy.alwaysCalledWithExactly({}, [], null)); }, "returns false for one exact match": function () { var object = {}; var array = []; this.spy({}, []); this.spy(object, []); this.spy(object, array); assert(this.spy.alwaysCalledWithExactly(object, array)); }, "returns true for only exact matches": function () { var object = {}; var array = []; this.spy(object, array); this.spy(object, array); this.spy(object, array); assert(this.spy.alwaysCalledWithExactly(object, array)); }, "returns false for no exact matches": function () { var object = {}; var array = []; this.spy(object, array, null); this.spy(object, array, undefined); this.spy(object, array, ""); assert.isFalse(this.spy.alwaysCalledWithExactly(object, array)); } }, ".threw": { setUp: function () { this.spy = sinon.spy.create(); this.spyWithTypeError = sinon.spy.create(function () { throw new TypeError(); }); this.spyWithStringError = sinon.spy.create(function () { throw "error"; }); }, "returns exception thrown by function": function () { var err = new Error(); var spy = sinon.spy.create(function () { throw err; }); try { spy(); } catch (e) {} // eslint-disable-line no-empty assert(spy.threw(err)); }, "returns false if spy did not throw": function () { this.spy(); assert.isFalse(this.spy.threw()); }, "returns true if spy threw": function () { try { this.spyWithTypeError(); } catch (e) {} // eslint-disable-line no-empty assert(this.spyWithTypeError.threw()); }, "returns true if string type matches": function () { try { this.spyWithTypeError(); } catch (e) {} // eslint-disable-line no-empty assert(this.spyWithTypeError.threw("TypeError")); }, "returns false if string did not match": function () { try { this.spyWithTypeError(); } catch (e) {} // eslint-disable-line no-empty assert.isFalse(this.spyWithTypeError.threw("Error")); }, "returns false if spy did not throw specified error": function () { this.spy(); assert.isFalse(this.spy.threw("Error")); }, "returns true if string matches": function () { try { this.spyWithStringError(); } catch (e) {} // eslint-disable-line no-empty assert(this.spyWithStringError.threw("error")); }, "returns false if strings do not match": function () { try { this.spyWithStringError(); } catch (e) {} // eslint-disable-line no-empty assert.isFalse(this.spyWithStringError.threw("not the error")); } }, ".alwaysThrew": { setUp: function () { this.spy = sinon.spy.create(); this.spyWithTypeError = sinon.spy.create(function () { throw new TypeError(); }); }, "returns true when spy threw": function () { var err = new Error(); var spy = sinon.spy.create(function () { throw err; }); try { spy(); } catch (e) {} // eslint-disable-line no-empty assert(spy.alwaysThrew(err)); }, "returns false if spy did not throw": function () { this.spy(); assert.isFalse(this.spy.alwaysThrew()); }, "returns true if spy threw": function () { try { this.spyWithTypeError(); } catch (e) {} // eslint-disable-line no-empty assert(this.spyWithTypeError.alwaysThrew()); }, "returns true if string type matches": function () { try { this.spyWithTypeError(); } catch (e) {} // eslint-disable-line no-empty assert(this.spyWithTypeError.alwaysThrew("TypeError")); }, "returns false if string did not match": function () { try { this.spyWithTypeError(); } catch (e) {} // eslint-disable-line no-empty assert.isFalse(this.spyWithTypeError.alwaysThrew("Error")); }, "returns false if spy did not throw specified error": function () { this.spy(); assert.isFalse(this.spy.alwaysThrew("Error")); }, "returns false if some calls did not throw": function () { var spy = sinon.stub.create(function () { if (spy.callCount === 0) { throw new Error(); } }); try { this.spy(); } catch (e) {} // eslint-disable-line no-empty this.spy(); assert.isFalse(this.spy.alwaysThrew()); }, "returns true if all calls threw": function () { /*eslint-disable no-empty*/ try { this.spyWithTypeError(); } catch (e1) {} try { this.spyWithTypeError(); } catch (e2) {} /*eslint-enable no-empty*/ assert(this.spyWithTypeError.alwaysThrew()); }, "returns true if all calls threw same type": function () { /*eslint-disable no-empty*/ try { this.spyWithTypeError(); } catch (e1) {} try { this.spyWithTypeError(); } catch (e2) {} /*eslint-enable no-empty*/ assert(this.spyWithTypeError.alwaysThrew("TypeError")); } }, ".exceptions": { setUp: function () { this.spy = sinon.spy.create(); var error = this.error = {}; this.spyWithTypeError = sinon.spy.create(function () { throw error; }); }, "contains exception thrown by function": function () { try { this.spyWithTypeError(); } catch (e) {} // eslint-disable-line no-empty assert.equals(this.spyWithTypeError.exceptions, [this.error]); }, "contains undefined entry when function did not throw": function () { this.spy(); assert.equals(this.spy.exceptions.length, 1); refute.defined(this.spy.exceptions[0]); }, "stacks up exceptions and undefined": function () { var calls = 0; var err = this.error; var spy = sinon.spy.create(function () { calls += 1; if (calls % 2 === 0) { throw err; } }); spy(); /*eslint-disable no-empty*/ try { spy(); } catch (e1) {} spy(); try { spy(); } catch (e2) {} /*eslint-enable no-empty*/ spy(); assert.equals(spy.exceptions.length, 5); refute.defined(spy.exceptions[0]); assert.equals(spy.exceptions[1], err); refute.defined(spy.exceptions[2]); assert.equals(spy.exceptions[3], err); refute.defined(spy.exceptions[4]); } }, ".returned": { "returns true when no argument": function () { var spy = sinon.spy.create(); spy(); assert(spy.returned()); }, "returns true for undefined when no explicit return": function () { var spy = sinon.spy.create(); spy(); assert(spy.returned(undefined)); }, "returns true when returned value once": function () { var values = [{}, 2, "hey", function () {}]; var spy = sinon.spy.create(function () { return values[spy.callCount]; }); spy(); spy(); spy(); spy(); assert(spy.returned(values[3])); }, "returns false when value is never returned": function () { var values = [{}, 2, "hey", function () {}]; var spy = sinon.spy.create(function () { return values[spy.callCount]; }); spy(); spy(); spy(); spy(); assert.isFalse(spy.returned({ id: 42 })); }, "returns true when value is returned several times": function () { var object = { id: 42 }; var spy = sinon.spy.create(function () { return object; }); spy(); spy(); spy(); assert(spy.returned(object)); }, "compares values deeply": function () { var object = { deep: { id: 42 } }; var spy = sinon.spy.create(function () { return object; }); spy(); assert(spy.returned({ deep: { id: 42 } })); }, "compares values strictly using match.same": function () { var object = { id: 42 }; var spy = sinon.spy.create(function () { return object; }); spy(); assert.isFalse(spy.returned(sinon.match.same({ id: 42 }))); assert(spy.returned(sinon.match.same(object))); } }, ".returnValues": { "contains undefined when function does not return explicitly": function () { var spy = sinon.spy.create(); spy(); assert.equals(spy.returnValues.length, 1); refute.defined(spy.returnValues[0]); }, "contains return value": function () { var object = { id: 42 }; var spy = sinon.spy.create(function () { return object; }); spy(); assert.equals(spy.returnValues, [object]); }, "contains undefined when function throws": function () { var spy = sinon.spy.create(function () { throw new Error(); }); try { spy(); } catch (e) {} // eslint-disable-line no-empty assert.equals(spy.returnValues.length, 1); refute.defined(spy.returnValues[0]); }, "contains the created object for spied constructors": function () { var Spy = sinon.spy.create(function () { }); var result = new Spy(); assert.equals(Spy.returnValues[0], result); }, "contains the return value for spied constructors that explicitly return objects": function () { var Spy = sinon.spy.create(function () { return { isExplicitlyCreatedValue: true }; }); var result = new Spy(); assert.isTrue(result.isExplicitlyCreatedValue); assert.equals(Spy.returnValues[0], result); }, "contains the created object for spied constructors that explicitly return primitive values": function () { var Spy = sinon.spy.create(function () { return 10; }); var result = new Spy(); refute.equals(result, 10); assert.equals(Spy.returnValues[0], result); }, "stacks up return values": function () { var calls = 0; var spy = sinon.spy.create(function () { calls += 1; if (calls % 2 === 0) { return calls; } }); spy(); spy(); spy(); spy(); spy(); assert.equals(spy.returnValues.length, 5); refute.defined(spy.returnValues[0]); assert.equals(spy.returnValues[1], 2); refute.defined(spy.returnValues[2]); assert.equals(spy.returnValues[3], 4); refute.defined(spy.returnValues[4]); } }, ".calledBefore": { setUp: function () { this.spy1 = sinon.spy(); this.spy2 = sinon.spy(); }, "is function": function () { assert.isFunction(this.spy1.calledBefore); }, "returns true if first call to A was before first to B": function () { this.spy1(); this.spy2(); assert(this.spy1.calledBefore(this.spy2)); }, "compares call order of calls directly": function () { this.spy1(); this.spy2(); assert(this.spy1.getCall(0).calledBefore(this.spy2.getCall(0))); }, "returns false if not called": function () { this.spy2(); assert.isFalse(this.spy1.calledBefore(this.spy2)); }, "returns true if other not called": function () { this.spy1(); assert(this.spy1.calledBefore(this.spy2)); }, "returns false if other called first": function () { this.spy2(); this.spy1(); this.spy2(); assert(this.spy1.calledBefore(this.spy2)); } }, ".calledAfter": { setUp: function () { this.spy1 = sinon.spy(); this.spy2 = sinon.spy(); }, "is function": function () { assert.isFunction(this.spy1.calledAfter); }, "returns true if first call to A was after first to B": function () { this.spy2(); this.spy1(); assert(this.spy1.calledAfter(this.spy2)); }, "compares calls directly": function () { this.spy2(); this.spy1(); assert(this.spy1.getCall(0).calledAfter(this.spy2.getCall(0))); }, "returns false if not called": function () { this.spy2(); assert.isFalse(this.spy1.calledAfter(this.spy2)); }, "returns false if other not called": function () { this.spy1(); assert.isFalse(this.spy1.calledAfter(this.spy2)); }, "returns false if other called last": function () { this.spy2(); this.spy1(); this.spy2(); assert.isFalse(this.spy1.calledAfter(this.spy2)); } }, ".firstCall": { "is undefined by default": function () { var spy = sinon.spy(); assert.isNull(spy.firstCall); }, "is equal to getCall(0) result after first call": function () { var spy = sinon.spy(); spy(); var call0 = spy.getCall(0); assert.equals(spy.firstCall.callId, call0.callId); assert.same(spy.firstCall.spy, call0.spy); }, "is equal to getCall(0) after first call when control flow has continued after invocation": function () { var spy; function runAsserts() { var call0 = spy.getCall(0); assert.equals(spy.firstCall.callId, call0.callId); assert.same(spy.firstCall.spy, call0.spy); } spy = sinon.spy(runAsserts); spy(); }, "is tracked even if exceptions are thrown": function () { var spy = sinon.spy(function () { throw "an exception"; }); try { spy(); } catch (e) {} // eslint-disable-line no-empty refute.isNull(spy.firstCall); }, "has correct returnValue": function () { var spy = sinon.spy(function () { return 42; }); spy(); assert.equals(spy.firstCall.returnValue, 42); assert(spy.firstCall.returned(42)); }, "has correct exception": function () { var err = new Error(); var spy = sinon.spy(function () { throw err; }); try { spy(); } catch (e) {} // eslint-disable-line no-empty assert.same(spy.firstCall.exception, err); assert(spy.firstCall.threw(err)); } }, ".secondCall": { "is null by default": function () { var spy = sinon.spy(); assert.isNull(spy.secondCall); }, "stills be null after first call": function () { var spy = sinon.spy(); spy(); assert.isNull(spy.secondCall); }, "is equal to getCall(1) result after second call": function () { var spy = sinon.spy(); spy(); spy(); var call1 = spy.getCall(1); assert.equals(spy.secondCall.callId, call1.callId); assert.same(spy.secondCall.spy, call1.spy); } }, ".thirdCall": { "is undefined by default": function () { var spy = sinon.spy(); assert.isNull(spy.thirdCall); }, "stills be undefined after second call": function () { var spy = sinon.spy(); spy(); spy(); assert.isNull(spy.thirdCall); }, "is equal to getCall(1) result after second call": function () { var spy = sinon.spy(); spy(); spy(); spy(); var call2 = spy.getCall(2); assert.equals(spy.thirdCall.callId, call2.callId); assert.same(spy.thirdCall.spy, call2.spy); } }, ".lastCall": { "is undefined by default": function () { var spy = sinon.spy(); assert.isNull(spy.lastCall); }, "is same as firstCall after first call": function () { var spy = sinon.spy(); spy(); assert.same(spy.lastCall.callId, spy.firstCall.callId); assert.same(spy.lastCall.spy, spy.firstCall.spy); }, "is same as secondCall after second call": function () { var spy = sinon.spy(); spy(); spy(); assert.same(spy.lastCall.callId, spy.secondCall.callId); assert.same(spy.lastCall.spy, spy.secondCall.spy); }, "is same as thirdCall after third call": function () { var spy = sinon.spy(); spy(); spy(); spy(); assert.same(spy.lastCall.callId, spy.thirdCall.callId); assert.same(spy.lastCall.spy, spy.thirdCall.spy); }, "is equal to getCall(3) result after fourth call": function () { var spy = sinon.spy(); spy(); spy(); spy(); spy(); var call3 = spy.getCall(3); assert.equals(spy.lastCall.callId, call3.callId); assert.same(spy.lastCall.spy, call3.spy); }, "is equal to getCall(4) result after fifth call": function () { var spy = sinon.spy(); spy(); spy(); spy(); spy(); spy(); var call4 = spy.getCall(4); assert.equals(spy.lastCall.callId, call4.callId); assert.same(spy.lastCall.spy, call4.spy); } }, ".getCalls": { "returns an empty Array by default": function () { var spy = sinon.spy(); assert.isArray(spy.getCalls()); assert.equals(spy.getCalls().length, 0); }, "is analogous to using getCall(n)": function () { var spy = sinon.spy(); spy(); spy(); assert.equals(spy.getCalls(), [spy.getCall(0), spy.getCall(1)]); } }, ".callArg": { "is function": function () { var spy = sinon.spy(); assert.isFunction(spy.callArg); }, "invokes argument at index for all calls": function () { var spy = sinon.spy(); var callback = sinon.spy(); spy(1, 2, callback); spy(3, 4, callback); spy.callArg(2); assert(callback.calledTwice); assert(callback.alwaysCalledWith()); }, "throws if argument at index is not a function": function () { var spy = sinon.spy(); spy(); assert.exception(function () { spy.callArg(1); }, "TypeError"); }, "throws if spy was not yet invoked": function () { var spy = sinon.spy(); try { spy.callArg(0); throw new Error(); } catch (e) { assert.equals(e.message, "spy cannot call arg since it was not yet invoked."); } }, "includes spy name in error message": function () { var api = { someMethod: function () {} }; var spy = sinon.spy(api, "someMethod"); try { spy.callArg(0); throw new Error(); } catch (e) { assert.equals(e.message, "someMethod cannot call arg since it was not yet invoked."); } }, "throws if index is not a number": function () { var spy = sinon.spy(); spy(); assert.exception(function () { spy.callArg(""); }, "TypeError"); }, "passs additional arguments": function () { var spy = sinon.spy(); var callback = sinon.spy(); var array = []; var object = {}; spy(callback); spy.callArg(0, "abc", 123, array, object); assert(callback.calledWith("abc", 123, array, object)); } }, ".callArgOn": { "is function": function () { var spy = sinon.spy(); assert.isFunction(spy.callArgOn); }, "invokes argument at index for all calls": function () { var spy = sinon.spy(); var callback = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; spy(1, 2, callback); spy(3, 4, callback); spy.callArgOn(2, thisObj); assert(callback.calledTwice); assert(callback.alwaysCalledWith()); assert(callback.alwaysCalledOn(thisObj)); }, "throws if argument at index is not a function": function () { var spy = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; spy(); assert.exception(function () { spy.callArgOn(1, thisObj); }, "TypeError"); }, "throws if spy was not yet invoked": function () { var spy = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; try { spy.callArgOn(0, thisObj); throw new Error(); } catch (e) { assert.equals(e.message, "spy cannot call arg since it was not yet invoked."); } }, "includes spy name in error message": function () { var api = { someMethod: function () {} }; var spy = sinon.spy(api, "someMethod"); var thisObj = { name1: "value1", name2: "value2" }; try { spy.callArgOn(0, thisObj); throw new Error(); } catch (e) { assert.equals(e.message, "someMethod cannot call arg since it was not yet invoked."); } }, "throws if index is not a number": function () { var spy = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; spy(); assert.exception(function () { spy.callArg("", thisObj); }, "TypeError"); }, "pass additional arguments": function () { var spy = sinon.spy(); var callback = sinon.spy(); var array = []; var object = {}; var thisObj = { name1: "value1", name2: "value2" }; spy(callback); spy.callArgOn(0, thisObj, "abc", 123, array, object); assert(callback.calledWith("abc", 123, array, object)); assert(callback.calledOn(thisObj)); } }, ".callArgWith": { "is alias for callArg": function () { var spy = sinon.spy(); assert.same(spy.callArgWith, spy.callArg); } }, ".callArgOnWith": { "is alias for callArgOn": function () { var spy = sinon.spy(); assert.same(spy.callArgOnWith, spy.callArgOn); } }, ".yield": { "is function": function () { var spy = sinon.spy(); assert.isFunction(spy.yield); }, "invokes first function arg for all calls": function () { var spy = sinon.spy(); var callback = sinon.spy(); spy(1, 2, callback); spy(3, 4, callback); spy.yield(); assert(callback.calledTwice); assert(callback.alwaysCalledWith()); }, "throws if spy was not yet invoked": function () { var spy = sinon.spy(); try { spy.yield(); throw new Error(); } catch (e) { assert.equals(e.message, "spy cannot yield since it was not yet invoked."); } }, "includes spy name in error message": function () { var api = { someMethod: function () {} }; var spy = sinon.spy(api, "someMethod"); try { spy.yield(); throw new Error(); } catch (e) { assert.equals(e.message, "someMethod cannot yield since it was not yet invoked."); } }, "passs additional arguments": function () { var spy = sinon.spy(); var callback = sinon.spy(); var array = []; var object = {}; spy(callback); spy.yield("abc", 123, array, object); assert(callback.calledWith("abc", 123, array, object)); } }, ".invokeCallback": { "is alias for yield": function () { var spy = sinon.spy(); assert.same(spy.invokeCallback, spy.yield); } }, ".yieldOn": { "is function": function () { var spy = sinon.spy(); assert.isFunction(spy.yieldOn); }, "invokes first function arg for all calls": function () { var spy = sinon.spy(); var callback = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; spy(1, 2, callback); spy(3, 4, callback); spy.yieldOn(thisObj); assert(callback.calledTwice); assert(callback.alwaysCalledWith()); assert(callback.alwaysCalledOn(thisObj)); }, "throws if spy was not yet invoked": function () { var spy = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; try { spy.yieldOn(thisObj); throw new Error(); } catch (e) { assert.equals(e.message, "spy cannot yield since it was not yet invoked."); } }, "includes spy name in error message": function () { var api = { someMethod: function () {} }; var spy = sinon.spy(api, "someMethod"); var thisObj = { name1: "value1", name2: "value2" }; try { spy.yieldOn(thisObj); throw new Error(); } catch (e) { assert.equals(e.message, "someMethod cannot yield since it was not yet invoked."); } }, "pass additional arguments": function () { var spy = sinon.spy(); var callback = sinon.spy(); var array = []; var object = {}; var thisObj = { name1: "value1", name2: "value2" }; spy(callback); spy.yieldOn(thisObj, "abc", 123, array, object); assert(callback.calledWith("abc", 123, array, object)); assert(callback.calledOn(thisObj)); } }, ".yieldTo": { "is function": function () { var spy = sinon.spy(); assert.isFunction(spy.yieldTo); }, "invokes first function arg for all calls": function () { var spy = sinon.spy(); var callback = sinon.spy(); spy(1, 2, { success: callback }); spy(3, 4, { success: callback }); spy.yieldTo("success"); assert(callback.calledTwice); assert(callback.alwaysCalledWith()); }, "throws if spy was not yet invoked": function () { var spy = sinon.spy(); try { spy.yieldTo("success"); throw new Error(); } catch (e) { assert.equals(e.message, "spy cannot yield to 'success' since it was not yet invoked."); } }, "includes spy name in error message": function () { var api = { someMethod: function () {} }; var spy = sinon.spy(api, "someMethod"); try { spy.yieldTo("success"); throw new Error(); } catch (e) { assert.equals(e.message, "someMethod cannot yield to 'success' since it was not yet invoked."); } }, "pass additional arguments": function () { var spy = sinon.spy(); var callback = sinon.spy(); var array = []; var object = {}; spy({ test: callback }); spy.yieldTo("test", "abc", 123, array, object); assert(callback.calledWith("abc", 123, array, object)); } }, ".yieldToOn": { "is function": function () { var spy = sinon.spy(); assert.isFunction(spy.yieldToOn); }, "invokes first function arg for all calls": function () { var spy = sinon.spy(); var callback = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; spy(1, 2, { success: callback }); spy(3, 4, { success: callback }); spy.yieldToOn("success", thisObj); assert(callback.calledTwice); assert(callback.alwaysCalledWith()); assert(callback.alwaysCalledOn(thisObj)); }, "throws if spy was not yet invoked": function () { var spy = sinon.spy(); var thisObj = { name1: "value1", name2: "value2" }; try { spy.yieldToOn("success", thisObj); throw new Error(); } catch (e) { assert.equals(e.message, "spy cannot yield to 'success' since it was not yet invoked."); } }, "includes spy name in error message": function () { var api = { someMethod: function () {} }; var spy = sinon.spy(api, "someMethod"); var thisObj = { name1: "value1", name2: "value2" }; try { spy.yieldToOn("success", thisObj); throw new Error(); } catch (e) { assert.equals(e.message, "someMethod cannot yield to 'success' since it was not yet invoked."); } }, "pass additional arguments": function () { var spy = sinon.spy(); var callback = sinon.spy(); var array = []; var object = {}; var thisObj = { name1: "value1", name2: "value2" }; spy({ test: callback }); spy.yieldToOn("test", thisObj, "abc", 123, array, object); assert(callback.calledWith("abc", 123, array, object)); assert(callback.calledOn(thisObj)); } }, ".reset": { "return same object": function () { var spy = sinon.spy(); var reset = spy.reset(); assert(reset === spy); }, "throws if called during spy invocation": function () { var spy = sinon.spy(function () { spy.reset(); }); assert.exception(function () { spy(); }, "InvalidResetException"); } }, ".length": { "is zero by default": function () { var spy = sinon.spy(); assert.equals(spy.length, 0); }, "matches the function length": function () { var api = { someMethod: function (a, b, c) {} }; // eslint-disable-line no-unused-vars var spy = sinon.spy(api, "someMethod"); assert.equals(spy.length, 3); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/stub-test.js000066400000000000000000001647771276775511300234060ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; var refute = buster.refute; var fail = buster.referee.fail; buster.testCase("sinon.stub", { "is spy": function () { var stub = sinon.stub.create(); assert.isFalse(stub.called); assert.isFunction(stub.calledWith); assert.isFunction(stub.calledOn); }, "should contain asynchronous versions of callsArg*, and yields* methods": function () { var stub = sinon.stub.create(); var syncVersions = 0; var asyncVersions = 0; for (var method in stub) { if (stub.hasOwnProperty(method) && method.match(/^(callsArg|yields)/)) { if (!method.match(/Async/)) { syncVersions++; } else if (method.match(/Async/)) { asyncVersions++; } } } assert.same(syncVersions, asyncVersions, "Stub prototype should contain same amount of synchronous and asynchronous methods"); }, "should allow overriding async behavior with sync behavior": function () { var stub = sinon.stub(); var callback = sinon.spy(); stub.callsArgAsync(1); stub.callsArg(1); stub(1, callback); assert(callback.called); }, ".returns": { "returns specified value": function () { var stub = sinon.stub.create(); var object = {}; stub.returns(object); assert.same(stub(), object); }, "returns should return stub": function () { var stub = sinon.stub.create(); assert.same(stub.returns(""), stub); }, "returns undefined": function () { var stub = sinon.stub.create(); refute.defined(stub()); }, "supersedes previous throws": function () { var stub = sinon.stub.create(); stub.throws().returns(1); refute.exception(function () { stub(); }); } }, ".returnsArg": { "returns argument at specified index": function () { var stub = sinon.stub.create(); stub.returnsArg(0); var object = {}; assert.same(stub(object), object); }, "returns stub": function () { var stub = sinon.stub.create(); assert.same(stub.returnsArg(0), stub); }, "throws if no index is specified": function () { var stub = sinon.stub.create(); assert.exception(function () { stub.returnsArg(); }, "TypeError"); }, "throws if index is not number": function () { var stub = sinon.stub.create(); assert.exception(function () { stub.returnsArg({}); }, "TypeError"); } }, ".returnsThis": { "stub returns this": function () { var instance = {}; instance.stub = sinon.stub.create(); instance.stub.returnsThis(); assert.same(instance.stub(), instance); }, "stub returns undefined when detached": { requiresSupportFor: { strictMode: (function () { return this; }()) === undefined }, "": function () { var stub = sinon.stub.create(); stub.returnsThis(); // Due to strict mode, would be `global` otherwise assert.same(stub(), undefined); } }, "stub respects call/apply": function () { var stub = sinon.stub.create(); stub.returnsThis(); var object = {}; assert.same(stub.call(object), object); assert.same(stub.apply(object), object); }, "returns stub": function () { var stub = sinon.stub.create(); assert.same(stub.returnsThis(), stub); } }, ".throws": { "throws specified exception": function () { var stub = sinon.stub.create(); var error = new Error(); stub.throws(error); try { stub(); fail("Expected stub to throw"); } catch (e) { assert.same(e, error); } }, "returns stub": function () { var stub = sinon.stub.create(); assert.same(stub.throws({}), stub); }, "sets type of exception to throw": function () { var stub = sinon.stub.create(); var exceptionType = "TypeError"; stub.throws(exceptionType); assert.exception(function () { stub(); }, exceptionType); }, "specifies exception message": function () { var stub = sinon.stub.create(); var message = "Oh no!"; stub.throws("Error", message); try { stub(); buster.referee.fail("Expected stub to throw"); } catch (e) { assert.equals(e.message, message); } }, "does not specify exception message if not provided": function () { var stub = sinon.stub.create(); stub.throws("Error"); try { stub(); buster.referee.fail("Expected stub to throw"); } catch (e) { assert.equals(e.message, ""); } }, "throws generic error": function () { var stub = sinon.stub.create(); stub.throws(); assert.exception(function () { stub(); }, "Error"); }, "resets 'invoking' flag": function () { var stub = sinon.stub.create(); stub.throws(); try { stub(); } catch (e) { refute.defined(stub.invoking); } } }, ".callsArg": { setUp: function () { this.stub = sinon.stub.create(); }, "calls argument at specified index": function () { this.stub.callsArg(2); var callback = sinon.stub.create(); this.stub(1, 2, callback); assert(callback.called); }, "returns stub": function () { assert.isFunction(this.stub.callsArg(2)); }, "throws if argument at specified index is not callable": function () { this.stub.callsArg(0); assert.exception(function () { this.stub(1); }, "TypeError"); }, "throws if no index is specified": function () { var stub = this.stub; assert.exception(function () { stub.callsArg(); }, "TypeError"); }, "throws if index is not number": function () { var stub = this.stub; assert.exception(function () { stub.callsArg({}); }, "TypeError"); } }, ".callsArgWith": { setUp: function () { this.stub = sinon.stub.create(); }, "calls argument at specified index with provided args": function () { var object = {}; this.stub.callsArgWith(1, object); var callback = sinon.stub.create(); this.stub(1, callback); assert(callback.calledWith(object)); }, "returns function": function () { var stub = this.stub.callsArgWith(2, 3); assert.isFunction(stub); }, "calls callback without args": function () { this.stub.callsArgWith(1); var callback = sinon.stub.create(); this.stub(1, callback); assert(callback.calledWith()); }, "calls callback with multiple args": function () { var object = {}; var array = []; this.stub.callsArgWith(1, object, array); var callback = sinon.stub.create(); this.stub(1, callback); assert(callback.calledWith(object, array)); }, "throws if no index is specified": function () { var stub = this.stub; assert.exception(function () { stub.callsArgWith(); }, "TypeError"); }, "throws if index is not number": function () { var stub = this.stub; assert.exception(function () { stub.callsArgWith({}); }, "TypeError"); } }, ".callsArgOn": { setUp: function () { this.stub = sinon.stub.create(); this.fakeContext = { foo: "bar" }; }, "calls argument at specified index": function () { this.stub.callsArgOn(2, this.fakeContext); var callback = sinon.stub.create(); this.stub(1, 2, callback); assert(callback.called); assert(callback.calledOn(this.fakeContext)); }, "returns stub": function () { var stub = this.stub.callsArgOn(2, this.fakeContext); assert.isFunction(stub); }, "throws if argument at specified index is not callable": function () { this.stub.callsArgOn(0, this.fakeContext); assert.exception(function () { this.stub(1); }, "TypeError"); }, "throws if no index is specified": function () { var stub = this.stub; assert.exception(function () { stub.callsArgOn(); }, "TypeError"); }, "throws if no context is specified": function () { var stub = this.stub; assert.exception(function () { stub.callsArgOn(3); }, "TypeError"); }, "throws if index is not number": function () { var stub = this.stub; assert.exception(function () { stub.callsArgOn(this.fakeContext, 2); }, "TypeError"); }, "throws if context is not an object": function () { var stub = this.stub; assert.exception(function () { stub.callsArgOn(2, 2); }, "TypeError"); } }, ".callsArgOnWith": { setUp: function () { this.stub = sinon.stub.create(); this.fakeContext = { foo: "bar" }; }, "calls argument at specified index with provided args": function () { var object = {}; this.stub.callsArgOnWith(1, this.fakeContext, object); var callback = sinon.stub.create(); this.stub(1, callback); assert(callback.calledWith(object)); assert(callback.calledOn(this.fakeContext)); }, "returns function": function () { var stub = this.stub.callsArgOnWith(2, this.fakeContext, 3); assert.isFunction(stub); }, "calls callback without args": function () { this.stub.callsArgOnWith(1, this.fakeContext); var callback = sinon.stub.create(); this.stub(1, callback); assert(callback.calledWith()); assert(callback.calledOn(this.fakeContext)); }, "calls callback with multiple args": function () { var object = {}; var array = []; this.stub.callsArgOnWith(1, this.fakeContext, object, array); var callback = sinon.stub.create(); this.stub(1, callback); assert(callback.calledWith(object, array)); assert(callback.calledOn(this.fakeContext)); }, "throws if no index is specified": function () { var stub = this.stub; assert.exception(function () { stub.callsArgOnWith(); }, "TypeError"); }, "throws if no context is specified": function () { var stub = this.stub; assert.exception(function () { stub.callsArgOnWith(3); }, "TypeError"); }, "throws if index is not number": function () { var stub = this.stub; assert.exception(function () { stub.callsArgOnWith({}); }, "TypeError"); }, "throws if context is not an object": function () { var stub = this.stub; assert.exception(function () { stub.callsArgOnWith(2, 2); }, "TypeError"); } }, ".objectMethod": { setUp: function () { this.method = function () {}; this.object = { method: this.method }; this.wrapMethod = sinon.wrapMethod; }, tearDown: function () { sinon.wrapMethod = this.wrapMethod; }, "returns function from wrapMethod": function () { var wrapper = function () {}; sinon.wrapMethod = function () { return wrapper; }; var result = sinon.stub(this.object, "method"); assert.same(result, wrapper); }, "passes object and method to wrapMethod": function () { var wrapper = function () {}; var args; sinon.wrapMethod = function () { args = arguments; return wrapper; }; sinon.stub(this.object, "method"); assert.same(args[0], this.object); assert.same(args[1], "method"); }, "uses provided function as stub": function () { var called = false; var stub = sinon.stub(this.object, "method", function () { called = true; }); stub(); assert(called); }, "wraps provided function": function () { var customStub = function () {}; var stub = sinon.stub(this.object, "method", customStub); refute.same(stub, customStub); assert.isFunction(stub.restore); }, "throws if third argument is provided but not a function or proprety descriptor": function () { var object = this.object; assert.exception(function () { sinon.stub(object, "method", 1); }, "TypeError"); }, "stubbed method should be proper stub": function () { var stub = sinon.stub(this.object, "method"); assert.isFunction(stub.returns); assert.isFunction(stub.throws); }, "custom stubbed method should not be proper stub": function () { var stub = sinon.stub(this.object, "method", function () {}); refute.defined(stub.returns); refute.defined(stub.throws); }, "stub should be spy": function () { var stub = sinon.stub(this.object, "method"); this.object.method(); assert(stub.called); assert(stub.calledOn(this.object)); }, "custom stubbed method should be spy": function () { var stub = sinon.stub(this.object, "method", function () {}); this.object.method(); assert(stub.called); assert(stub.calledOn(this.object)); }, "stub should affect spy": function () { var stub = sinon.stub(this.object, "method"); stub.throws("TypeError"); try { this.object.method(); } catch (e) {} // eslint-disable-line no-empty assert(stub.threw("TypeError")); }, "returns standalone stub without arguments": function () { var stub = sinon.stub(); assert.isFunction(stub); assert.isFalse(stub.called); }, "throws if property is not a function": function () { var obj = { someProp: 42 }; assert.exception(function () { sinon.stub(obj, "someProp"); }); assert.equals(obj.someProp, 42); }, "successfully stubs falsey properties": function () { var obj = { 0: function () { } }; sinon.stub(obj, 0, function () { return "stubbed value"; }); assert.equals(obj[0](), "stubbed value"); }, "does not stub function object": function () { assert.exception(function () { sinon.stub(function () {}); }); } }, everything: { "stubs all methods of object without property": function () { var obj = { func1: function () {}, func2: function () {}, func3: function () {} }; sinon.stub(obj); assert.isFunction(obj.func1.restore); assert.isFunction(obj.func2.restore); assert.isFunction(obj.func3.restore); }, "stubs prototype methods": function () { function Obj() {} Obj.prototype.func1 = function () {}; var obj = new Obj(); sinon.stub(obj); assert.isFunction(obj.func1.restore); }, "returns object": function () { var object = {}; assert.same(sinon.stub(object), object); }, "only stubs functions": function () { var object = { foo: "bar" }; sinon.stub(object); assert.equals(object.foo, "bar"); }, "handles non-enumerable properties": function () { var obj = { func1: function () {}, func2: function () {} }; Object.defineProperty(obj, "func3", { value: function () {}, writable: true, configurable: true }); sinon.stub(obj); assert.isFunction(obj.func1.restore); assert.isFunction(obj.func2.restore); assert.isFunction(obj.func3.restore); }, "handles non-enumerable properties on prototypes": function () { function Obj() {} Object.defineProperty(Obj.prototype, "func1", { value: function () {}, writable: true, configurable: true }); var obj = new Obj(); sinon.stub(obj); assert.isFunction(obj.func1.restore); }, "does not stub non-enumerable properties from Object.prototype": function () { var obj = {}; sinon.stub(obj); refute.isFunction(obj.toString.restore); refute.isFunction(obj.toLocaleString.restore); refute.isFunction(obj.propertyIsEnumerable.restore); }, "does not fail on overrides": function () { var parent = { func: function () {} }; var child = sinon.create(parent); child.func = function () {}; refute.exception(function () { sinon.stub(child); }); } }, "stubbed function": { "throws if stubbing non-existent property": function () { var myObj = {}; assert.exception(function () { sinon.stub(myObj, "ouch"); }); refute.defined(myObj.ouch); }, "has toString method": function () { var obj = { meth: function () {} }; sinon.stub(obj, "meth"); assert.equals(obj.meth.toString(), "meth"); }, "toString should say 'stub' when unable to infer name": function () { var stub = sinon.stub(); assert.equals(stub.toString(), "stub"); }, "toString should prefer property name if possible": function () { var obj = {}; obj.meth = sinon.stub(); obj.meth(); assert.equals(obj.meth.toString(), "meth"); } }, ".yields": { "invokes only argument as callback": function () { var stub = sinon.stub().yields(); var spy = sinon.spy(); stub(spy); assert(spy.calledOnce); assert.equals(spy.args[0].length, 0); }, "throws understandable error if no callback is passed": function () { var stub = sinon.stub().yields(); try { stub(); throw new Error(); } catch (e) { assert.equals(e.message, "stub expected to yield, but no callback was passed."); } }, "includes stub name and actual arguments in error": function () { var myObj = { somethingAwesome: function () {} }; var stub = sinon.stub(myObj, "somethingAwesome").yields(); try { stub(23, 42); throw new Error(); } catch (e) { assert.equals(e.message, "somethingAwesome expected to yield, but no callback " + "was passed. Received [23, 42]"); } }, "invokes last argument as callback": function () { var stub = sinon.stub().yields(); var spy = sinon.spy(); stub(24, {}, spy); assert(spy.calledOnce); assert.equals(spy.args[0].length, 0); }, "invokes first of two callbacks": function () { var stub = sinon.stub().yields(); var spy = sinon.spy(); var spy2 = sinon.spy(); stub(24, {}, spy, spy2); assert(spy.calledOnce); assert(!spy2.called); }, "invokes callback with arguments": function () { var obj = { id: 42 }; var stub = sinon.stub().yields(obj, "Crazy"); var spy = sinon.spy(); stub(spy); assert(spy.calledWith(obj, "Crazy")); }, "throws if callback throws": function () { var obj = { id: 42 }; var stub = sinon.stub().yields(obj, "Crazy"); var callback = sinon.stub().throws(); assert.exception(function () { stub(callback); }); }, "plays nice with throws": function () { var stub = sinon.stub().throws().yields(); var spy = sinon.spy(); assert.exception(function () { stub(spy); }); assert(spy.calledOnce); }, "plays nice with returns": function () { var obj = {}; var stub = sinon.stub().returns(obj).yields(); var spy = sinon.spy(); assert.same(stub(spy), obj); assert(spy.calledOnce); }, "plays nice with returnsArg": function () { var stub = sinon.stub().returnsArg(0).yields(); var spy = sinon.spy(); assert.same(stub(spy), spy); assert(spy.calledOnce); }, "plays nice with returnsThis": function () { var obj = {}; var stub = sinon.stub().returnsThis().yields(); var spy = sinon.spy(); assert.same(stub.call(obj, spy), obj); assert(spy.calledOnce); } }, ".yieldsRight": { "invokes only argument as callback": function () { var stub = sinon.stub().yieldsRight(); var spy = sinon.spy(); stub(spy); assert(spy.calledOnce); assert.equals(spy.args[0].length, 0); }, "throws understandable error if no callback is passed": function () { var stub = sinon.stub().yieldsRight(); try { stub(); throw new Error(); } catch (e) { assert.equals(e.message, "stub expected to yield, but no callback was passed."); } }, "includes stub name and actual arguments in error": function () { var myObj = { somethingAwesome: function () {} }; var stub = sinon.stub(myObj, "somethingAwesome").yieldsRight(); try { stub(23, 42); throw new Error(); } catch (e) { assert.equals(e.message, "somethingAwesome expected to yield, but no callback " + "was passed. Received [23, 42]"); } }, "invokes last argument as callback": function () { var stub = sinon.stub().yieldsRight(); var spy = sinon.spy(); stub(24, {}, spy); assert(spy.calledOnce); assert.equals(spy.args[0].length, 0); }, "invokes the last of two callbacks": function () { var stub = sinon.stub().yieldsRight(); var spy = sinon.spy(); var spy2 = sinon.spy(); stub(24, {}, spy, spy2); assert(!spy.called); assert(spy2.calledOnce); }, "invokes callback with arguments": function () { var obj = { id: 42 }; var stub = sinon.stub().yieldsRight(obj, "Crazy"); var spy = sinon.spy(); stub(spy); assert(spy.calledWith(obj, "Crazy")); }, "throws if callback throws": function () { var obj = { id: 42 }; var stub = sinon.stub().yieldsRight(obj, "Crazy"); var callback = sinon.stub().throws(); assert.exception(function () { stub(callback); }); }, "plays nice with throws": function () { var stub = sinon.stub().throws().yieldsRight(); var spy = sinon.spy(); assert.exception(function () { stub(spy); }); assert(spy.calledOnce); }, "plays nice with returns": function () { var obj = {}; var stub = sinon.stub().returns(obj).yieldsRight(); var spy = sinon.spy(); assert.same(stub(spy), obj); assert(spy.calledOnce); }, "plays nice with returnsArg": function () { var stub = sinon.stub().returnsArg(0).yieldsRight(); var spy = sinon.spy(); assert.same(stub(spy), spy); assert(spy.calledOnce); }, "plays nice with returnsThis": function () { var obj = {}; var stub = sinon.stub().returnsThis().yieldsRight(); var spy = sinon.spy(); assert.same(stub.call(obj, spy), obj); assert(spy.calledOnce); } }, ".yieldsOn": { setUp: function () { this.stub = sinon.stub.create(); this.fakeContext = { foo: "bar" }; }, "invokes only argument as callback": function () { var spy = sinon.spy(); this.stub.yieldsOn(this.fakeContext); this.stub(spy); assert(spy.calledOnce); assert(spy.calledOn(this.fakeContext)); assert.equals(spy.args[0].length, 0); }, "throws if no context is specified": function () { assert.exception(function () { this.stub.yieldsOn(); }, "TypeError"); }, "throws understandable error if no callback is passed": function () { this.stub.yieldsOn(this.fakeContext); try { this.stub(); throw new Error(); } catch (e) { assert.equals(e.message, "stub expected to yield, but no callback was passed."); } }, "includes stub name and actual arguments in error": function () { var myObj = { somethingAwesome: function () {} }; var stub = sinon.stub(myObj, "somethingAwesome").yieldsOn(this.fakeContext); try { stub(23, 42); throw new Error(); } catch (e) { assert.equals(e.message, "somethingAwesome expected to yield, but no callback " + "was passed. Received [23, 42]"); } }, "invokes last argument as callback": function () { var spy = sinon.spy(); this.stub.yieldsOn(this.fakeContext); this.stub(24, {}, spy); assert(spy.calledOnce); assert(spy.calledOn(this.fakeContext)); assert.equals(spy.args[0].length, 0); }, "invokes first of two callbacks": function () { var spy = sinon.spy(); var spy2 = sinon.spy(); this.stub.yieldsOn(this.fakeContext); this.stub(24, {}, spy, spy2); assert(spy.calledOnce); assert(spy.calledOn(this.fakeContext)); assert(!spy2.called); }, "invokes callback with arguments": function () { var obj = { id: 42 }; var spy = sinon.spy(); this.stub.yieldsOn(this.fakeContext, obj, "Crazy"); this.stub(spy); assert(spy.calledWith(obj, "Crazy")); assert(spy.calledOn(this.fakeContext)); }, "throws if callback throws": function () { var obj = { id: 42 }; var callback = sinon.stub().throws(); this.stub.yieldsOn(this.fakeContext, obj, "Crazy"); assert.exception(function () { this.stub(callback); }); } }, ".yieldsTo": { "yields to property of object argument": function () { var stub = sinon.stub().yieldsTo("success"); var callback = sinon.spy(); stub({ success: callback }); assert(callback.calledOnce); assert.equals(callback.args[0].length, 0); }, "throws understandable error if no object with callback is passed": function () { var stub = sinon.stub().yieldsTo("success"); try { stub(); throw new Error(); } catch (e) { assert.equals(e.message, "stub expected to yield to 'success', but no object " + "with such a property was passed."); } }, "includes stub name and actual arguments in error": function () { var myObj = { somethingAwesome: function () {} }; var stub = sinon.stub(myObj, "somethingAwesome").yieldsTo("success"); try { stub(23, 42); throw new Error(); } catch (e) { assert.equals(e.message, "somethingAwesome expected to yield to 'success', but " + "no object with such a property was passed. " + "Received [23, 42]"); } }, "invokes property on last argument as callback": function () { var stub = sinon.stub().yieldsTo("success"); var callback = sinon.spy(); stub(24, {}, { success: callback }); assert(callback.calledOnce); assert.equals(callback.args[0].length, 0); }, "invokes first of two possible callbacks": function () { var stub = sinon.stub().yieldsTo("error"); var callback = sinon.spy(); var callback2 = sinon.spy(); stub(24, {}, { error: callback }, { error: callback2 }); assert(callback.calledOnce); assert(!callback2.called); }, "invokes callback with arguments": function () { var obj = { id: 42 }; var stub = sinon.stub().yieldsTo("success", obj, "Crazy"); var callback = sinon.spy(); stub({ success: callback }); assert(callback.calledWith(obj, "Crazy")); }, "throws if callback throws": function () { var obj = { id: 42 }; var stub = sinon.stub().yieldsTo("error", obj, "Crazy"); var callback = sinon.stub().throws(); assert.exception(function () { stub({ error: callback }); }); } }, ".yieldsToOn": { setUp: function () { this.stub = sinon.stub.create(); this.fakeContext = { foo: "bar" }; }, "yields to property of object argument": function () { this.stub.yieldsToOn("success", this.fakeContext); var callback = sinon.spy(); this.stub({ success: callback }); assert(callback.calledOnce); assert(callback.calledOn(this.fakeContext)); assert.equals(callback.args[0].length, 0); }, "throws if no context is specified": function () { assert.exception(function () { this.stub.yieldsToOn("success"); }, "TypeError"); }, "throws understandable error if no object with callback is passed": function () { this.stub.yieldsToOn("success", this.fakeContext); try { this.stub(); throw new Error(); } catch (e) { assert.equals(e.message, "stub expected to yield to 'success', but no object " + "with such a property was passed."); } }, "includes stub name and actual arguments in error": function () { var myObj = { somethingAwesome: function () {} }; var stub = sinon.stub(myObj, "somethingAwesome").yieldsToOn("success", this.fakeContext); try { stub(23, 42); throw new Error(); } catch (e) { assert.equals(e.message, "somethingAwesome expected to yield to 'success', but " + "no object with such a property was passed. " + "Received [23, 42]"); } }, "invokes property on last argument as callback": function () { var callback = sinon.spy(); this.stub.yieldsToOn("success", this.fakeContext); this.stub(24, {}, { success: callback }); assert(callback.calledOnce); assert(callback.calledOn(this.fakeContext)); assert.equals(callback.args[0].length, 0); }, "invokes first of two possible callbacks": function () { var callback = sinon.spy(); var callback2 = sinon.spy(); this.stub.yieldsToOn("error", this.fakeContext); this.stub(24, {}, { error: callback }, { error: callback2 }); assert(callback.calledOnce); assert(callback.calledOn(this.fakeContext)); assert(!callback2.called); }, "invokes callback with arguments": function () { var obj = { id: 42 }; var callback = sinon.spy(); this.stub.yieldsToOn("success", this.fakeContext, obj, "Crazy"); this.stub({ success: callback }); assert(callback.calledOn(this.fakeContext)); assert(callback.calledWith(obj, "Crazy")); }, "throws if callback throws": function () { var obj = { id: 42 }; var callback = sinon.stub().throws(); this.stub.yieldsToOn("error", this.fakeContext, obj, "Crazy"); assert.exception(function () { this.stub({ error: callback }); }); } }, ".withArgs": { "defines withArgs method": function () { var stub = sinon.stub(); assert.isFunction(stub.withArgs); }, "creates filtered stub": function () { var stub = sinon.stub(); var other = stub.withArgs(23); refute.same(other, stub); assert.isFunction(stub.returns); assert.isFunction(other.returns); }, "filters return values based on arguments": function () { var stub = sinon.stub().returns(23); stub.withArgs(42).returns(99); assert.equals(stub(), 23); assert.equals(stub(42), 99); }, "filters exceptions based on arguments": function () { var stub = sinon.stub().returns(23); stub.withArgs(42).throws(); refute.exception(stub); assert.exception(function () { stub(42); }); } }, ".callsArgAsync": { setUp: function () { this.stub = sinon.stub.create(); }, "asynchronously calls argument at specified index": function (done) { this.stub.callsArgAsync(2); var callback = sinon.spy(done); this.stub(1, 2, callback); assert(!callback.called); } }, ".callsArgWithAsync": { setUp: function () { this.stub = sinon.stub.create(); }, "asynchronously calls callback at specified index with multiple args": function (done) { var object = {}; var array = []; this.stub.callsArgWithAsync(1, object, array); var callback = sinon.spy(done(function () { assert(callback.calledWith(object, array)); })); this.stub(1, callback); assert(!callback.called); } }, ".callsArgOnAsync": { setUp: function () { this.stub = sinon.stub.create(); this.fakeContext = { foo: "bar" }; }, "asynchronously calls argument at specified index with specified context": function (done) { var context = this.fakeContext; this.stub.callsArgOnAsync(2, context); var callback = sinon.spy(done(function () { assert(callback.calledOn(context)); })); this.stub(1, 2, callback); assert(!callback.called); } }, ".callsArgOnWithAsync": { setUp: function () { this.stub = sinon.stub.create(); this.fakeContext = { foo: "bar" }; }, "asynchronously calls argument at specified index with provided context and args": function (done) { var object = {}; var context = this.fakeContext; this.stub.callsArgOnWithAsync(1, context, object); var callback = sinon.spy(done(function () { assert(callback.calledOn(context)); assert(callback.calledWith(object)); })); this.stub(1, callback); assert(!callback.called); } }, ".yieldsAsync": { "asynchronously invokes only argument as callback": function (done) { var stub = sinon.stub().yieldsAsync(); var spy = sinon.spy(done); stub(spy); assert(!spy.called); } }, ".yieldsOnAsync": { setUp: function () { this.stub = sinon.stub.create(); this.fakeContext = { foo: "bar" }; }, "asynchronously invokes only argument as callback with given context": function (done) { var context = this.fakeContext; this.stub.yieldsOnAsync(context); var spy = sinon.spy(done(function () { assert(spy.calledOnce); assert(spy.calledOn(context)); assert.equals(spy.args[0].length, 0); })); this.stub(spy); assert(!spy.called); } }, ".yieldsToAsync": { "asynchronously yields to property of object argument": function (done) { var stub = sinon.stub().yieldsToAsync("success"); var callback = sinon.spy(done(function () { assert(callback.calledOnce); assert.equals(callback.args[0].length, 0); })); stub({ success: callback }); assert(!callback.called); } }, ".yieldsToOnAsync": { setUp: function () { this.stub = sinon.stub.create(); this.fakeContext = { foo: "bar" }; }, "asynchronously yields to property of object argument with given context": function (done) { var context = this.fakeContext; this.stub.yieldsToOnAsync("success", context); var callback = sinon.spy(done(function () { assert(callback.calledOnce); assert(callback.calledOn(context)); assert.equals(callback.args[0].length, 0); })); this.stub({ success: callback }); assert(!callback.called); } }, ".onCall": { "can be used with returns to produce sequence": function () { var stub = sinon.stub().returns(3); stub.onFirstCall().returns(1) .onCall(2).returns(2); assert.same(stub(), 1); assert.same(stub(), 3); assert.same(stub(), 2); assert.same(stub(), 3); }, "can be used with returnsArg to produce sequence": function () { var stub = sinon.stub().returns("default"); stub.onSecondCall().returnsArg(0); assert.same(stub(1), "default"); assert.same(stub(2), 2); assert.same(stub(3), "default"); }, "can be used with returnsThis to produce sequence": function () { var instance = {}; instance.stub = sinon.stub().returns("default"); instance.stub.onSecondCall().returnsThis(); assert.same(instance.stub(), "default"); assert.same(instance.stub(), instance); assert.same(instance.stub(), "default"); }, "can be used with throwsException to produce sequence": function () { var stub = sinon.stub(); var error = new Error(); stub.onSecondCall().throwsException(error); stub(); try { stub(); fail("Expected stub to throw"); } catch (e) { assert.same(e, error); } }, "in combination with withArgs": { "can produce a sequence for a fake": function () { var stub = sinon.stub().returns(0); stub.withArgs(5).returns(-1) .onFirstCall().returns(1) .onSecondCall().returns(2); assert.same(stub(0), 0); assert.same(stub(5), 1); assert.same(stub(0), 0); assert.same(stub(5), 2); assert.same(stub(5), -1); }, "falls back to stub default behaviour if fake does not have its own default behaviour": function () { var stub = sinon.stub().returns(0); stub.withArgs(5) .onFirstCall().returns(1); assert.same(stub(5), 1); assert.same(stub(5), 0); }, "falls back to stub behaviour for call if fake does not have its own behaviour for call": function () { var stub = sinon.stub().returns(0); stub.withArgs(5).onFirstCall().returns(1); stub.onSecondCall().returns(2); assert.same(stub(5), 1); assert.same(stub(5), 2); assert.same(stub(4), 0); }, "defaults to undefined behaviour once no more calls have been defined": function () { var stub = sinon.stub(); stub.withArgs(5).onFirstCall().returns(1) .onSecondCall().returns(2); assert.same(stub(5), 1); assert.same(stub(5), 2); refute.defined(stub(5)); }, "does not create undefined behaviour just by calling onCall": function () { var stub = sinon.stub().returns(2); stub.onFirstCall(); assert.same(stub(6), 2); }, "works with fakes and reset": function () { var stub = sinon.stub(); stub.withArgs(5).onFirstCall().returns(1); stub.withArgs(5).onSecondCall().returns(2); assert.same(stub(5), 1); assert.same(stub(5), 2); refute.defined(stub(5)); stub.reset(); assert.same(stub(5), 1); assert.same(stub(5), 2); refute.defined(stub(5)); }, "throws an understandable error when trying to use withArgs on behavior": function () { try { sinon.stub().onFirstCall().withArgs(1); } catch (e) { assert.match(e.message, /not supported/); } } }, "can be used with yields* to produce a sequence": function () { var context = { foo: "bar" }; var obj = { method1: sinon.spy(), method2: sinon.spy() }; var obj2 = { method2: sinon.spy() }; var stub = sinon.stub().yieldsToOn("method2", context, 7, 8); stub.onFirstCall().yields(1, 2) .onSecondCall().yieldsOn(context, 3, 4) .onThirdCall().yieldsTo("method1", 5, 6) .onCall(3).yieldsToOn("method2", context, 7, 8); var spy1 = sinon.spy(); var spy2 = sinon.spy(); stub(spy1); stub(spy2); stub(obj); stub(obj); stub(obj2); // should continue with default behavior assert(spy1.calledOnce); assert(spy1.calledWithExactly(1, 2)); assert(spy2.calledOnce); assert(spy2.calledAfter(spy1)); assert(spy2.calledOn(context)); assert(spy2.calledWithExactly(3, 4)); assert(obj.method1.calledOnce); assert(obj.method1.calledAfter(spy2)); assert(obj.method1.calledWithExactly(5, 6)); assert(obj.method2.calledOnce); assert(obj.method2.calledAfter(obj.method1)); assert(obj.method2.calledOn(context)); assert(obj.method2.calledWithExactly(7, 8)); assert(obj2.method2.calledOnce); assert(obj2.method2.calledAfter(obj.method2)); assert(obj2.method2.calledOn(context)); assert(obj2.method2.calledWithExactly(7, 8)); }, "can be used with callsArg* to produce a sequence": function () { var spy1 = sinon.spy(); var spy2 = sinon.spy(); var spy3 = sinon.spy(); var spy4 = sinon.spy(); var spy5 = sinon.spy(); var decoy = sinon.spy(); var context = { foo: "bar" }; var stub = sinon.stub().callsArgOnWith(3, context, "c", "d"); stub.onFirstCall().callsArg(0) .onSecondCall().callsArgWith(1, "a", "b") .onThirdCall().callsArgOn(2, context) .onCall(3).callsArgOnWith(3, context, "c", "d"); stub(spy1); stub(decoy, spy2); stub(decoy, decoy, spy3); stub(decoy, decoy, decoy, spy4); stub(decoy, decoy, decoy, spy5); // should continue with default behavior assert(spy1.calledOnce); assert(spy2.calledOnce); assert(spy2.calledAfter(spy1)); assert(spy2.calledWithExactly("a", "b")); assert(spy3.calledOnce); assert(spy3.calledAfter(spy2)); assert(spy3.calledOn(context)); assert(spy4.calledOnce); assert(spy4.calledAfter(spy3)); assert(spy4.calledOn(context)); assert(spy4.calledWithExactly("c", "d")); assert(spy5.calledOnce); assert(spy5.calledAfter(spy4)); assert(spy5.calledOn(context)); assert(spy5.calledWithExactly("c", "d")); assert(decoy.notCalled); }, "can be used with yields* and callsArg* in combination to produce a sequence": function () { var stub = sinon.stub().yields(1, 2); stub.onSecondCall().callsArg(1) .onThirdCall().yieldsTo("method") .onCall(3).callsArgWith(2, "a", "b"); var obj = { method: sinon.spy() }; var spy1 = sinon.spy(); var spy2 = sinon.spy(); var spy3 = sinon.spy(); var decoy = sinon.spy(); stub(spy1); stub(decoy, spy2); stub(obj); stub(decoy, decoy, spy3); assert(spy1.calledOnce); assert(spy2.calledOnce); assert(spy2.calledAfter(spy1)); assert(obj.method.calledOnce); assert(obj.method.calledAfter(spy2)); assert(spy3.calledOnce); assert(spy3.calledAfter(obj.method)); assert(spy3.calledWithExactly("a", "b")); assert(decoy.notCalled); }, "should interact correctly with assertions (GH-231)": function () { var stub = sinon.stub(); var spy = sinon.spy(); stub.callsArgWith(0, "a"); stub(spy); assert(spy.calledWith("a")); stub(spy); assert(spy.calledWith("a")); stub.onThirdCall().callsArgWith(0, "b"); stub(spy); assert(spy.calledWith("b")); } }, "reset only resets call history": function () { var obj = { a: function () {} }; var spy = sinon.spy(); sinon.stub(obj, "a").callsArg(1); obj.a(null, spy); obj.a.reset(); obj.a(null, spy); assert(spy.calledTwice); }, ".resetBehavior": { "clears yields* and callsArg* sequence": function () { var stub = sinon.stub().yields(1); stub.onFirstCall().callsArg(1); stub.resetBehavior(); stub.yields(3); var spyWanted = sinon.spy(); var spyNotWanted = sinon.spy(); stub(spyWanted, spyNotWanted); assert(spyNotWanted.notCalled); assert(spyWanted.calledOnce); assert(spyWanted.calledWithExactly(3)); }, "cleans 'returns' behavior": function () { var stub = sinon.stub().returns(1); stub.resetBehavior(); refute.defined(stub()); }, "cleans behavior of fakes returned by withArgs": function () { var stub = sinon.stub(); stub.withArgs("lolz").returns(2); stub.resetBehavior(); refute.defined(stub("lolz")); }, "does not clean parents' behavior when called on a fake returned by withArgs": function () { var parentStub = sinon.stub().returns(false); var childStub = parentStub.withArgs("lolz").returns(true); childStub.resetBehavior(); assert.same(parentStub("lolz"), false); assert.same(parentStub(), false); }, "cleans 'returnsArg' behavior": function () { var stub = sinon.stub().returnsArg(0); stub.resetBehavior(); refute.defined(stub("defined")); }, "cleans 'returnsThis' behavior": function () { var instance = {}; instance.stub = sinon.stub.create(); instance.stub.returnsThis(); instance.stub.resetBehavior(); refute.defined(instance.stub()); }, "does not touch properties that are reset by 'reset'": { ".calledOnce": function () { var stub = sinon.stub(); stub(1); stub.resetBehavior(); assert(stub.calledOnce); }, "called multiple times": function () { var stub = sinon.stub(); stub(1); stub(2); stub(3); stub.resetBehavior(); assert(stub.called); assert.equals(stub.args.length, 3); assert.equals(stub.returnValues.length, 3); assert.equals(stub.exceptions.length, 3); assert.equals(stub.thisValues.length, 3); assert.defined(stub.firstCall); assert.defined(stub.secondCall); assert.defined(stub.thirdCall); assert.defined(stub.lastCall); }, "call order state": function () { var stubs = [sinon.stub(), sinon.stub()]; stubs[0](); stubs[1](); stubs[0].resetBehavior(); assert(stubs[0].calledBefore(stubs[1])); }, "fakes returned by withArgs": function () { var stub = sinon.stub(); var fakeA = stub.withArgs("a"); var fakeB = stub.withArgs("b"); stub("a"); stub("b"); stub("c"); var fakeC = stub.withArgs("c"); stub.resetBehavior(); assert(fakeA.calledOnce); assert(fakeB.calledOnce); assert(fakeC.calledOnce); } } }, ".length": { "is zero by default": function () { var stub = sinon.stub(); assert.equals(stub.length, 0); }, "matches the function length": function () { var api = { someMethod: function (a, b, c) {} }; // eslint-disable-line no-unused-vars var stub = sinon.stub(api, "someMethod"); assert.equals(stub.length, 3); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/test-case-test.js000066400000000000000000000167311276775511300243030ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; var refute = buster.refute; buster.testCase("sinon.testCase", { "throws without argument": function () { assert.exception(function () { sinon.testCase(); }, "TypeError"); }, "throws without object": function () { assert.exception(function () { sinon.testCase(function () {}); }, "TypeError"); }, "only wraps functions with test prefix": sinon.test(function () { this.spy(sinon, "test"); var testc = { testA: function () {}, doB: function () {} }; sinon.testCase(testc); assert.isFunction(testc.doB); assert(sinon.test.calledWith(testc.testA)); assert.isFalse(sinon.test.calledWith(testc.doB)); }), "removes setUp method": function () { var test = { setUp: function () {} }; var result = sinon.testCase(test); refute.defined(result.setUp); refute.defined(result["test setUp"]); }, "removes tearDown method": function () { var test = { tearDown: function () {} }; var result = sinon.testCase(test); refute.defined(result.tearDown); refute.defined(result["test tearDown"]); }, "calls setUp before any test": function () { var test = { setUp: sinon.stub(), test: sinon.stub(), test2: sinon.stub() }; var result = sinon.testCase(test); result.test(); result.test2(); assert.equals(test.setUp.callCount, 2); sinon.assert.called(test.test); sinon.assert.called(test.test2); }, "calls tearDown after any test": function () { var test = { tearDown: sinon.stub(), test: sinon.stub(), test2: sinon.stub() }; var result = sinon.testCase(test); result.test(); result.test2(); refute.exception(function () { sinon.assert.called(test.tearDown); sinon.assert.called(test.test); sinon.assert.called(test.test2); }); }, "calls tearDown even if test throws": function () { var test = { tearDown: sinon.stub(), test: sinon.stub().throws() }; var result = sinon.testCase(test); assert.exception(function () { result.test(); }, "Error"); sinon.assert.called(test.tearDown); sinon.assert.called(test.test); }, "calls setUp test tearDown in order": function () { var testCase = { setUp: sinon.stub(), test: sinon.stub(), tearDown: sinon.stub() }; var result = sinon.testCase(testCase); try { result.test(); } catch (e) {} // eslint-disable-line no-empty refute.exception(function () { sinon.assert.callOrder(testCase.setUp, testCase.test, testCase.tearDown); }); }, "calls in order when test throws": function () { var testCase = { setUp: sinon.stub(), tearDown: sinon.stub(), test: sinon.stub().throws() }; var result = sinon.testCase(testCase); try { result.test(); } catch (e) {} // eslint-disable-line no-empty refute.exception(function () { sinon.assert.callOrder(testCase.setUp, testCase.test, testCase.tearDown); }); }, "unstubs objects after test is run": function () { var myMeth = function () {}; var myObj = { meth: myMeth }; var testCase = sinon.testCase({ testA: function () { this.stub(myObj, "meth"); assert.isFunction(this.stub); refute.same(myObj.meth, myMeth); } }); testCase.testA(); assert.same(myObj.meth, myMeth); }, "unstubs all methods of an objects after test is run": function () { var myMeth = function () {}; var myMeth2 = function () {}; var myObj = { meth: myMeth, meth2: myMeth2 }; var testCase = sinon.testCase({ testA: function () { this.stub(myObj); assert.isFunction(this.stub); refute.same(myObj.meth, myMeth); refute.same(myObj.meth2, myMeth2); } }); testCase.testA(); assert.same(myObj.meth, myMeth); assert.same(myObj.meth2, myMeth2); }, "unstubs objects stubbed in setUp": function () { var myMeth = function () {}; var myObj = { meth: myMeth }; var testCase = sinon.testCase({ setUp: function () { this.stub(myObj, "meth"); }, testA: function () { assert.isFunction(this.stub); refute.same(myObj.meth, myMeth); } }); testCase.testA(); assert.same(myObj.meth, myMeth); }, "unstubs all methods of an objects stubbed in setUp": function () { var myMeth = function () {}; var myMeth2 = function () {}; var myObj = { meth: myMeth, meth2: myMeth2 }; var testCase = sinon.testCase({ setUp: function () { this.stub(myObj); }, testA: function () { assert.isFunction(this.stub); refute.same(myObj.meth, myMeth); refute.same(myObj.meth2, myMeth2); } }); testCase.testA(); assert.same(myObj.meth, myMeth); assert.same(myObj.meth2, myMeth2); }, "allows the use of helper methods": function () { var helper = sinon.spy(); var testC = sinon.testCase({ doIt: helper, testIt: function () { this.doIt(); } }); refute.exception(function () { testC.testIt(); }); assert(helper.calledOnce); assert(helper.calledOn(testC)); }, "returns result of test function": function () { var testC = sinon.testCase({ testIt: sinon.stub().returns(42) }); assert.equals(testC.testIt(), 42); }, "returns result of test function with setUp": function () { var testC = sinon.testCase({ setUp: sinon.spy(), testIt: sinon.stub().returns(42) }); assert.equals(testC.testIt(), 42); }, "returns result of test function with setUp and teardown": function () { var testC = sinon.testCase({ setUp: sinon.spy(), tearDown: sinon.spy(), testIt: sinon.stub().returns(42) }); assert.equals(testC.testIt(), 42); } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/test-helper.js000066400000000000000000000030011276775511300236540ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); buster.referee.add("spy", { assert: function (obj) { return obj !== null && typeof obj.calledWith === "function" && !obj.returns; }, assertMessage: "Expected object ${0} to be a spy function" }); buster.referee.add("stub", { assert: function (obj) { return obj !== null && typeof obj.calledWith === "function" && typeof obj.returns === "function"; }, assertMessage: "Expected object ${0} to be a stub function" }); buster.referee.add("mock", { assert: function (obj) { return obj !== null && typeof obj.verify === "function" && typeof obj.expects === "function"; }, assertMessage: "Expected object ${0} to be a mock" }); buster.referee.add("fakeServer", { assert: function (obj) { return obj !== null && Object.prototype.toString.call(obj.requests) === "[object Array]" && typeof obj.respondWith === "function"; }, assertMessage: "Expected object ${0} to be a fake server" }); buster.referee.add("clock", { assert: function (obj) { return obj !== null && typeof obj.tick === "function" && typeof obj.setTimeout === "function"; }, assertMessage: "Expected object ${0} to be a clock" }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/test-test.js000066400000000000000000000470031276775511300233660ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var nextTick = buster.nextTick || require("buster-core").nextTick; var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; var refute = buster.refute; buster.testCase("sinon.test", { setUp: function () { this.boundTestCase = function () { var properties = { fn: function () { properties.self = this; properties.args = arguments; properties.spy = this.spy; properties.stub = this.stub; properties.mock = this.mock; properties.clock = this.clock; properties.server = this.server; properties.requests = this.requests; properties.sandbox = this.sandbox; } }; return properties; }; }, tearDown: function () { sinon.config = {}; }, "throws if argument is not a function": function () { assert.exception(function () { sinon.test({}); }); }, "proxies return value": function () { var object = {}; var result = sinon.test(function () { return object; })(); assert.same(result, object); }, "stubs inside sandbox": function () { var method = function () {}; var object = { method: method }; sinon.test(function () { this.stub(object, "method").returns(object); assert.same(object.method(), object); }).call({}); }, "restores stubs": function () { var method = function () {}; var object = { method: method }; sinon.test(function () { this.stub(object, "method"); }).call({}); assert.same(object.method, method); }, "restores stubs on all object methods": function () { var method = function () {}; var method2 = function () {}; var object = { method: method, method2: method2 }; sinon.test(function () { this.stub(object); }).call({}); assert.same(object.method, method); assert.same(object.method2, method2); }, "throws when method throws": function () { var method = function () {}; var object = { method: method }; assert.exception(function () { sinon.test(function () { this.stub(object, "method"); throw new Error(); }).call({}); }, "Error"); }, "throws when an async method throws": function () { var method = function () {}; var object = { method: method }; var fakeDone = function () {}; assert.exception(function () { sinon.test(function (done) { // eslint-disable-line no-unused-vars this.stub(object, "method"); throw new Error(); }).call({}, fakeDone); }, "Error"); }, "restores stub when method throws": function () { var method = function () {}; var object = { method: method }; try { sinon.test(function () { this.stub(object, "method"); throw new Error(); }).call({}); } catch (e) {} // eslint-disable-line no-empty assert.same(object.method, method); }, "mocks inside sandbox": function () { var method = function () {}; var object = { method: method }; sinon.test(function () { this.mock(object).expects("method").returns(object); assert.same(object.method(), object); }).call({}); }, "passes on errors to callbacks": function () { var fn = sinon.test(function (callback) { callback(new Error("myerror")); }); function errorChecker(err) { errorChecker.called = true; assert.equals(err instanceof Error, true); } fn(errorChecker); assert.equals(errorChecker.called, true); }, "async test with sandbox": function (done) { var fakeDone = function (args) { assert.equals(args, undefined); done(args); }; sinon.test(function (callback) { nextTick(function () { callback(); }); }).call({}, fakeDone); }, "async test with sandbox using mocha interface": function (done) { var it = function (title, fn) { var mochaDone = function (args) { assert.equals(args, undefined); done(args); }; if (fn.length) { fn.call(this, mochaDone); } else { fn.call(this); } }; it("works", sinon.test(function (callback) { nextTick(function () { callback(); }); })); }, "async test with sandbox using mocha interface throwing error": function (done) { var it = function (title, fn) { var mochaDone = function (args) { assert.equals(args, undefined); done(args); }; if (fn.length) { fn.call(this, mochaDone); } else { fn.call(this); } }; it("works", sinon.test(function (callback) { callback(); })); }, "async test with sandbox and spy": function (done) { sinon.test(function (callback) { var globalObj = { addOne: function (arg) { return this.addOneInner(arg); }, addOneInner: function (arg) { return arg + 1; } }; var addOneInnerSpy = this.spy(); this.stub(globalObj, "addOneInner", addOneInnerSpy); nextTick(function () { globalObj.addOne(41); assert(addOneInnerSpy.calledOnce); callback(); }); }).call({}, done); }, "async test preserves additional args and pass them in correct order": function (done) { sinon.test(function (arg1, arg2, callback) { assert.equals(arg1, "arg1"); assert.equals(typeof (arg2), "object"); assert.equals(typeof (callback), "function"); callback(); }).call({}, "arg1", {}, done); }, "verifies mocks": function () { var method = function () {}; var object = { method: method }; var exception; try { sinon.test(function () { this.mock(object).expects("method").withExactArgs(1).once(); object.method(42); }).call({}); } catch (e) { exception = e; } assert.same(exception.name, "ExpectationError"); assert.equals(exception.message, "Unexpected call: method(42)\n" + " Expected method(1) once (never called)"); assert.same(object.method, method); }, "restores mocks": function () { var method = function () {}; var object = { method: method }; try { sinon.test(function () { this.mock(object).expects("method"); }).call({}); } catch (e) {} // eslint-disable-line no-empty assert.same(object.method, method); }, "restores mock when method throws": function () { var method = function () {}; var object = { method: method }; try { sinon.test(function () { this.mock(object).expects("method").never(); object.method(); }).call({}); } catch (e) {} // eslint-disable-line no-empty assert.same(object.method, method); }, "appends helpers after normal arguments": function () { var object = { method: function () {} }; sinon.config = { injectIntoThis: false, properties: ["stub", "mock"] }; sinon.test(function (obj, stub, mock) { mock(object).expects("method").once(); object.method(); assert.same(obj, object); })(object); }, "maintains the this value": function () { var testCase = { someTest: sinon.test(function () { return this; }) }; assert.same(testCase.someTest(), testCase); }, "configurable test with sandbox": { tearDown: function () { sinon.config = {}; }, "yields stub, mock as arguments": function () { var stubbed, mocked; var obj = { meth: function () {} }; sinon.config = { injectIntoThis: false, properties: ["stub", "mock"] }; sinon.test(function (stub, mock) { stubbed = stub(obj, "meth"); mocked = mock(obj); assert.equals(arguments.length, 2); })(); assert.stub(stubbed); assert.mock(mocked); }, "yields spy, stub, mock as arguments": function () { var spied, stubbed, mocked; var obj = { meth: function () {} }; sinon.config = { injectIntoThis: false, properties: ["spy", "stub", "mock"] }; sinon.test(function (spy, stub, mock) { spied = spy(obj, "meth"); spied.restore(); stubbed = stub(obj, "meth"); mocked = mock(obj); assert.equals(arguments.length, 3); })(); assert.spy(spied); assert.stub(stubbed); assert.mock(mocked); }, "does not yield server when not faking xhr": function () { var stubbed, mocked; var obj = { meth: function () {} }; sinon.config = { injectIntoThis: false, properties: ["server", "stub", "mock"], useFakeServer: false }; sinon.test(function (stub, mock) { stubbed = stub(obj, "meth"); mocked = mock(obj); assert.equals(arguments.length, 2); })(); assert.stub(stubbed); assert.mock(mocked); }, "browser options": { requiresSupportFor: { "ajax/browser": typeof XMLHttpRequest !== "undefined" || typeof ActiveXObject !== "undefined" }, "yields server when faking xhr": function () { var stubbed, mocked, server; var obj = { meth: function () {} }; sinon.config = { injectIntoThis: false, properties: ["server", "stub", "mock"] }; sinon.test(function (serv, stub, mock) { server = serv; stubbed = stub(obj, "meth"); mocked = mock(obj); assert.equals(arguments.length, 3); })(); assert.fakeServer(server); assert.stub(stubbed); assert.mock(mocked); }, "uses serverWithClock when faking xhr": function () { var server; sinon.config = { injectIntoThis: false, properties: ["server"], useFakeServer: sinon.fakeServerWithClock }; sinon.test(function (serv) { server = serv; })(); assert.fakeServer(server); assert(sinon.fakeServerWithClock.isPrototypeOf(server)); }, "injects properties into object": function () { var obj = {}; sinon.config = { injectIntoThis: false, injectInto: obj, properties: ["server", "clock", "spy", "stub", "mock", "requests"] }; function testFunction() { assert.equals(arguments.length, 0); refute.defined(this.server); refute.defined(this.clock); refute.defined(this.spy); refute.defined(this.stub); refute.defined(this.mock); refute.defined(this.requests); assert.fakeServer(obj.server); assert.clock(obj.clock); assert.isFunction(obj.spy); assert.isFunction(obj.stub); assert.isFunction(obj.mock); assert.isArray(obj.requests); } sinon.test(testFunction).call({}); }, "injects server and clock when only enabling them": function () { sinon.config = { useFakeTimers: true, useFakeServer: true }; function testFunction() { assert.equals(arguments.length, 0); assert.isFunction(this.spy); assert.isFunction(this.stub); assert.isFunction(this.mock); assert.fakeServer(this.server); assert.isArray(this.requests); assert.clock(this.clock); refute.defined(this.sandbox); } sinon.test(testFunction).call({}); } }, "yields clock when faking timers": function () { var clock; sinon.config = { injectIntoThis: false, properties: ["clock"] }; sinon.test(function (c) { clock = c; assert.equals(arguments.length, 1); })(); assert.clock(clock); }, "fakes specified timers": function () { var props; sinon.config = { injectIntoThis: false, properties: ["clock"], useFakeTimers: ["Date", "setTimeout", "setImmediate"] }; sinon.test(function (c) { props = { clock: c, Date: Date, setTimeout: setTimeout, clearTimeout: clearTimeout, // clear & setImmediate are not yet available in all environments setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate : undefined), setInterval: setInterval, clearInterval: clearInterval }; })(); refute.same(props.Date, sinon.timers.Date); refute.same(props.setTimeout, sinon.timers.setTimeout); assert.same(props.clearTimeout, sinon.timers.clearTimeout); refute.same(props.setImmediate, sinon.timers.setImmediate); assert.same(props.clearImmediate, sinon.timers.clearImmediate); assert.same(props.setInterval, sinon.timers.setInterval); assert.same(props.clearInterval, sinon.timers.clearInterval); }, "injects properties into test case": function () { var testCase = {}; sinon.config = { properties: ["clock"] }; function testFunction() { assert.same(this, testCase); assert.equals(arguments.length, 0); assert.clock(this.clock); refute.defined(this.spy); refute.defined(this.stub); refute.defined(this.mock); } sinon.test(testFunction).call(testCase); }, "injects functions into test case by default": function () { function testFunction() { assert.equals(arguments.length, 0); assert.isFunction(this.spy); assert.isFunction(this.stub); assert.isFunction(this.mock); assert.isObject(this.clock); } sinon.test(testFunction).call({}); }, "injects sandbox": function () { function testFunction() { assert.equals(arguments.length, 0); assert.isFunction(this.spy); assert.isObject(this.sandbox); } sinon.config = { properties: ["sandbox", "spy"] }; sinon.test(testFunction).call({}); }, "remove injected properties afterwards": function () { var testCase = {}; sinon.test(function () {}).call(testCase); refute.defined(testCase.spy); refute.defined(testCase.stub); refute.defined(testCase.mock); refute.defined(testCase.sandbox); refute.defined(testCase.clock); refute.defined(testCase.server); refute.defined(testCase.requests); }, "uses sinon.test to fake time": function () { sinon.config = { useFakeTimers: true }; var called; var testCase = { test: sinon.test(function () { var spy = this.spy(); setTimeout(spy, 19); this.clock.tick(19); called = spy.called; }) }; testCase.test(); assert(called); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/times-in-words-test.js000066400000000000000000000025061276775511300252670ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; buster.testCase("sinon.timesInWords", { "should return \"once\" for input of 1": function () { var result = sinon.timesInWords(1); assert.equals(result, "once"); }, "should return \"twice\" for input of 2": function () { var result = sinon.timesInWords(2); assert.equals(result, "twice"); }, "should return \"thrice\" for input of 3": function () { var result = sinon.timesInWords(3); assert.equals(result, "thrice"); }, "should return \"n times\" for n larger than 3": function () { var result, i; for (i = 4; i < 100; i++) { result = sinon.timesInWords(i); assert.equals(result, i + " times"); } }, "should return \"0 times\" for falsy input": function () { var falsies = [0, NaN, null, false, undefined, ""]; var result, i; for (i = 0; i < falsies.length; i++) { result = sinon.timesInWords(falsies[i]); assert.equals(result, "0 times"); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/typeOf-test.js000066400000000000000000000025021276775511300236500ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; buster.testCase("sinon.typeOf", { "returns boolean": function () { assert.equals(sinon.typeOf(false), "boolean"); }, "returns string": function () { assert.equals(sinon.typeOf("Sinon.JS"), "string"); }, "returns number": function () { assert.equals(sinon.typeOf(123), "number"); }, "returns object": function () { assert.equals(sinon.typeOf({}), "object"); }, "returns function": function () { assert.equals(sinon.typeOf(function () {}), "function"); }, "returns undefined": function () { assert.equals(sinon.typeOf(undefined), "undefined"); }, "returns null": function () { assert.equals(sinon.typeOf(null), "null"); }, "returns array": function () { assert.equals(sinon.typeOf([]), "array"); }, "returns regexp": function () { assert.equals(sinon.typeOf(/.*/), "regexp"); }, "returns date": function () { assert.equals(sinon.typeOf(new Date()), "date"); } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/util/000077500000000000000000000000001276775511300220455ustar00rootroot00000000000000sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/util/event-test.js000066400000000000000000000110431276775511300245000ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../../lib/sinon"); var assert = buster.assert; buster.testCase("sinon.EventTarget", { setUp: function () { this.target = sinon.extend({}, sinon.EventTarget); }, "notifies event listener": function () { var listener = sinon.spy(); this.target.addEventListener("dummy", listener); var event = new sinon.Event("dummy"); this.target.dispatchEvent(event); assert(listener.calledOnce); assert(listener.calledWith(event)); }, "notifies event listener with target as this": function () { var listener = sinon.spy(); this.target.addEventListener("dummy", listener); var event = new sinon.Event("dummy"); this.target.dispatchEvent(event); assert(listener.calledOn(this.target)); }, "notifies all event listeners": function () { var listeners = [sinon.spy(), sinon.spy()]; this.target.addEventListener("dummy", listeners[0]); this.target.addEventListener("dummy", listeners[1]); var event = new sinon.Event("dummy"); this.target.dispatchEvent(event); assert(listeners[0].calledOnce); assert(listeners[0].calledOnce); }, "notifies event listener of type listener": function () { var listener = { handleEvent: sinon.spy() }; this.target.addEventListener("dummy", listener); this.target.dispatchEvent(new sinon.Event("dummy")); assert(listener.handleEvent.calledOnce); }, "does not notify listeners of other events": function () { var listeners = [sinon.spy(), sinon.spy()]; this.target.addEventListener("dummy", listeners[0]); this.target.addEventListener("other", listeners[1]); this.target.dispatchEvent(new sinon.Event("dummy")); assert.isFalse(listeners[1].called); }, "does not notify unregistered listeners": function () { var listener = sinon.spy(); this.target.addEventListener("dummy", listener); this.target.removeEventListener("dummy", listener); this.target.dispatchEvent(new sinon.Event("dummy")); assert.isFalse(listener.called); }, "notifies existing listeners after removing one": function () { var listeners = [sinon.spy(), sinon.spy(), sinon.spy()]; this.target.addEventListener("dummy", listeners[0]); this.target.addEventListener("dummy", listeners[1]); this.target.addEventListener("dummy", listeners[2]); this.target.removeEventListener("dummy", listeners[1]); this.target.dispatchEvent(new sinon.Event("dummy")); assert(listeners[0].calledOnce); assert(listeners[2].calledOnce); }, "returns false when event.preventDefault is not called": function () { this.target.addEventListener("dummy", sinon.spy()); var event = new sinon.Event("dummy"); var result = this.target.dispatchEvent(event); assert.isFalse(result); }, "returns true when event.preventDefault is called": function () { this.target.addEventListener("dummy", function (e) { e.preventDefault(); }); var result = this.target.dispatchEvent(new sinon.Event("dummy")); assert.isTrue(result); }, "notifies ProgressEvent listener with progress data ": function () { var listener = sinon.spy(); this.target.addEventListener("dummyProgress", listener); var progressEvent = new sinon.ProgressEvent("dummyProgress", {loaded: 50, total: 120}); this.target.dispatchEvent(progressEvent); assert.isTrue(progressEvent.lengthComputable); assert(listener.calledOnce); assert(listener.calledWith(progressEvent)); }, "notifies CustomEvent listener with custom data": function () { var listener = sinon.spy(); this.target.addEventListener("dummyCustom", listener); var customEvent = new sinon.CustomEvent("dummyCustom", {detail: "hola"}); this.target.dispatchEvent(customEvent); assert(listener.calledOnce); assert(listener.calledWith(customEvent)); } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/util/fake-server-test.js000066400000000000000000000761621276775511300256060ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../../lib/sinon"); var assert = buster.assert; var refute = buster.refute; // we need better ways to test both paths // but at least running tests in different environments will do that var FakeXHR = sinon.xhr.supportsCORS ? sinon.FakeXMLHttpRequest : sinon.FakeXDomainRequest; buster.testCase("sinon.fakeServer", { requiresSupportFor: { "browser": typeof window !== "undefined" }, tearDown: function () { if (this.server) { this.server.restore(); } }, "provides restore method": function () { this.server = sinon.fakeServer.create(); assert.isFunction(this.server.restore); }, ".create": { "allows the 'autoRespond' setting": function () { var server = sinon.fakeServer.create({ autoRespond: true }); assert( server.autoRespond, "fakeServer.create should accept 'autoRespond' setting" ); }, "allows the 'autoRespondAfter' setting": function () { var server = sinon.fakeServer.create({ autoRespondAfter: 500 }); assert.equals( server.autoRespondAfter, 500, "fakeServer.create should accept 'autoRespondAfter' setting" ); }, "allows the 'respondImmediately' setting": function () { var server = sinon.fakeServer.create({ respondImmediately: true }); assert( server.respondImmediately, "fakeServer.create should accept 'respondImmediately' setting" ); }, "allows the 'fakeHTTPMethods' setting": function () { var server = sinon.fakeServer.create({ fakeHTTPMethods: true }); assert( server.fakeHTTPMethods, "fakeServer.create should accept 'fakeHTTPMethods' setting" ); }, "does not assign a non-whitelisted setting": function () { var server = sinon.fakeServer.create({ foo: true }); refute( server.foo, "fakeServer.create should not accept 'foo' settings" ); } }, "fakes XMLHttpRequest": sinon.test(function () { this.stub(sinon, "useFakeXMLHttpRequest").returns({ restore: this.stub() }); this.server = sinon.fakeServer.create(); assert(sinon.useFakeXMLHttpRequest.called); }), "mirrors FakeXMLHttpRequest restore method": sinon.test(function () { this.server = sinon.fakeServer.create(); var restore = this.stub(sinon.FakeXMLHttpRequest, "restore"); this.server.restore(); assert(restore.called); }), ".requests": { setUp: function () { this.server = sinon.fakeServer.create(); }, tearDown: function () { this.server.restore(); }, "collects objects created with fake XHR": function () { var xhrs = [new FakeXHR(), new FakeXHR()]; assert.equals(this.server.requests, xhrs); }, "collects xhr objects through addRequest": function () { this.server.addRequest = sinon.spy(); var xhr = new FakeXHR(); assert(this.server.addRequest.calledWith(xhr)); }, "observes onSend on requests": function () { var xhrs = [new FakeXHR(), new FakeXHR()]; assert.isFunction(xhrs[0].onSend); assert.isFunction(xhrs[1].onSend); }, "onSend should call handleRequest with request object": function () { var xhr = new FakeXHR(); xhr.open("GET", "/"); sinon.spy(this.server, "handleRequest"); xhr.send(); assert(this.server.handleRequest.called); assert(this.server.handleRequest.calledWith(xhr)); } }, ".handleRequest": { setUp: function () { this.server = sinon.fakeServer.create(); }, tearDown: function () { this.server.restore(); }, "responds to synchronous requests": function () { var xhr = new FakeXHR(); xhr.open("GET", "/", false); sinon.spy(xhr, "respond"); xhr.send(); assert(xhr.respond.called); }, "does not respond to async requests": function () { var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/", true); sinon.spy(xhr, "respond"); xhr.send(); assert.isFalse(xhr.respond.called); } }, ".respondWith": { setUp: function () { this.sandbox = sinon.sandbox.create(); this.server = sinon.fakeServer.create(); this.getRootAsync = new sinon.FakeXMLHttpRequest(); this.getRootAsync.open("GET", "/", true); this.getRootAsync.send(); sinon.spy(this.getRootAsync, "respond"); this.postRootAsync = new sinon.FakeXMLHttpRequest(); this.postRootAsync.open("POST", "/", true); this.postRootAsync.send(); sinon.spy(this.postRootAsync, "respond"); this.getRootSync = new sinon.FakeXMLHttpRequest(); this.getRootSync.open("GET", "/", false); this.getPathAsync = new sinon.FakeXMLHttpRequest(); this.getPathAsync.open("GET", "/path", true); this.getPathAsync.send(); sinon.spy(this.getPathAsync, "respond"); this.postPathAsync = new sinon.FakeXMLHttpRequest(); this.postPathAsync.open("POST", "/path", true); this.postPathAsync.send(); sinon.spy(this.postPathAsync, "respond"); }, tearDown: function () { this.server.restore(); this.sandbox.restore(); }, "responds to queued async requests": function () { this.server.respondWith("Oh yeah! Duffman!"); this.server.respond(); assert(this.getRootAsync.respond.called); assert.equals(this.getRootAsync.respond.args[0], [200, {}, "Oh yeah! Duffman!"]); }, "responds to all queued async requests": function () { this.server.respondWith("Oh yeah! Duffman!"); this.server.respond(); assert(this.getRootAsync.respond.called); assert(this.getPathAsync.respond.called); }, "does not respond to requests queued after respond() (eg from callbacks)": function () { var xhr; this.getRootAsync.addEventListener("load", function () { xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/", true); xhr.send(); sinon.spy(xhr, "respond"); }); this.server.respondWith("Oh yeah! Duffman!"); this.server.respond(); assert(this.getRootAsync.respond.called); assert(this.getPathAsync.respond.called); assert(!xhr.respond.called); this.server.respond(); assert(xhr.respond.called); }, "responds with status, headers, and body": function () { var headers = { "Content-Type": "X-test" }; this.server.respondWith([201, headers, "Oh yeah!"]); this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [201, headers, "Oh yeah!"]); }, "handles responding with empty queue": function () { delete this.server.queue; var server = this.server; refute.exception(function () { server.respond(); }); }, "responds to sync request with canned answers": function () { this.server.respondWith([210, { "X-Ops": "Yeah" }, "Body, man"]); this.getRootSync.send(); assert.equals(this.getRootSync.status, 210); assert.equals(this.getRootSync.getAllResponseHeaders(), "X-Ops: Yeah\r\n"); assert.equals(this.getRootSync.responseText, "Body, man"); }, "responds to sync request with 404 if no response is set": function () { this.getRootSync.send(); assert.equals(this.getRootSync.status, 404); assert.equals(this.getRootSync.getAllResponseHeaders(), ""); assert.equals(this.getRootSync.responseText, ""); }, "responds to async request with 404 if no response is set": function () { this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [404, {}, ""]); }, "responds to specific URL": function () { this.server.respondWith("/path", "Duffman likes Duff beer"); this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [404, {}, ""]); assert.equals(this.getPathAsync.respond.args[0], [200, {}, "Duffman likes Duff beer"]); }, "responds to URL matched by regexp": function () { this.server.respondWith(/^\/p.*/, "Regexp"); this.server.respond(); assert.equals(this.getPathAsync.respond.args[0], [200, {}, "Regexp"]); }, "does not respond to URL not matched by regexp": function () { this.server.respondWith(/^\/p.*/, "No regexp match"); this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [404, {}, ""]); }, "responds to all URLs matched by regexp": function () { this.server.respondWith(/^\/.*/, "Match all URLs"); this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [200, {}, "Match all URLs"]); assert.equals(this.getPathAsync.respond.args[0], [200, {}, "Match all URLs"]); }, "responds to all requests when match URL is falsy": function () { this.server.respondWith("", "Falsy URL"); this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [200, {}, "Falsy URL"]); assert.equals(this.getPathAsync.respond.args[0], [200, {}, "Falsy URL"]); }, "responds to all GET requests": function () { this.server.respondWith("GET", "", "All GETs"); this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [200, {}, "All GETs"]); assert.equals(this.getPathAsync.respond.args[0], [200, {}, "All GETs"]); assert.equals(this.postRootAsync.respond.args[0], [404, {}, ""]); assert.equals(this.postPathAsync.respond.args[0], [404, {}, ""]); }, "responds to all 'get' requests (case-insensitivity)": function () { this.server.respondWith("get", "", "All GETs"); this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [200, {}, "All GETs"]); assert.equals(this.getPathAsync.respond.args[0], [200, {}, "All GETs"]); assert.equals(this.postRootAsync.respond.args[0], [404, {}, ""]); assert.equals(this.postPathAsync.respond.args[0], [404, {}, ""]); }, "responds to all PUT requests": function () { this.server.respondWith("PUT", "", "All PUTs"); this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [404, {}, ""]); assert.equals(this.getPathAsync.respond.args[0], [404, {}, ""]); assert.equals(this.postRootAsync.respond.args[0], [404, {}, ""]); assert.equals(this.postPathAsync.respond.args[0], [404, {}, ""]); }, "responds to all POST requests": function () { this.server.respondWith("POST", "", "All POSTs"); this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [404, {}, ""]); assert.equals(this.getPathAsync.respond.args[0], [404, {}, ""]); assert.equals(this.postRootAsync.respond.args[0], [200, {}, "All POSTs"]); assert.equals(this.postPathAsync.respond.args[0], [200, {}, "All POSTs"]); }, "responds to all POST requests to /path": function () { this.server.respondWith("POST", "/path", "All POSTs"); this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [404, {}, ""]); assert.equals(this.getPathAsync.respond.args[0], [404, {}, ""]); assert.equals(this.postRootAsync.respond.args[0], [404, {}, ""]); assert.equals(this.postPathAsync.respond.args[0], [200, {}, "All POSTs"]); }, "responds to all POST requests matching regexp": function () { this.server.respondWith("POST", /^\/path(\?.*)?/, "All POSTs"); this.server.respond(); assert.equals(this.getRootAsync.respond.args[0], [404, {}, ""]); assert.equals(this.getPathAsync.respond.args[0], [404, {}, ""]); assert.equals(this.postRootAsync.respond.args[0], [404, {}, ""]); assert.equals(this.postPathAsync.respond.args[0], [200, {}, "All POSTs"]); }, "does not respond to aborted requests": function () { this.server.respondWith("/", "That's my homepage!"); this.getRootAsync.aborted = true; this.server.respond(); assert.isFalse(this.getRootAsync.respond.called); }, "resets requests": function () { this.server.respondWith("/", "That's my homepage!"); this.server.respond(); assert.equals(this.server.queue, []); }, "notifies all requests when some throw": function () { this.sandbox.stub(sinon, "logError"); // reduce console spam in the test runner this.getRootAsync.respond = function () { throw new Error("Oops!"); }; this.server.respondWith(""); this.server.respond(); assert.equals(this.getPathAsync.respond.args[0], [200, {}, ""]); assert.equals(this.postRootAsync.respond.args[0], [200, {}, ""]); assert.equals(this.postPathAsync.respond.args[0], [200, {}, ""]); }, "recognizes request with hostname": function () { this.server.respondWith("/", [200, {}, "Yep"]); var xhr = new sinon.FakeXMLHttpRequest(); var loc = window.location; xhr.open("GET", loc.protocol + "//" + loc.host + "/", true); xhr.send(); sinon.spy(xhr, "respond"); this.server.respond(); assert.equals(xhr.respond.args[0], [200, {}, "Yep"]); }, "throws understandable error if response is not a string": function () { var error; try { this.server.respondWith("/", {}); } catch (e) { error = e; } assert.isObject(error); assert.equals(error.message, "Fake server response body should be string, but was object"); }, "throws understandable error if response in array is not a string": function () { var error; try { this.server.respondWith("/", [200, {}]); } catch (e) { error = e; } assert.isObject(error); assert.equals(error.message, "Fake server response body should be string, but was undefined"); }, "is able to pass the same args to respond directly": function () { this.server.respond("Oh yeah! Duffman!"); assert.equals(this.getRootAsync.respond.args[0], [200, {}, "Oh yeah! Duffman!"]); assert.equals(this.getPathAsync.respond.args[0], [200, {}, "Oh yeah! Duffman!"]); assert.equals(this.postRootAsync.respond.args[0], [200, {}, "Oh yeah! Duffman!"]); assert.equals(this.postPathAsync.respond.args[0], [200, {}, "Oh yeah! Duffman!"]); }, "responds to most recently defined match": function () { this.server.respondWith("POST", "", "All POSTs"); this.server.respondWith("POST", "/path", "Particular POST"); this.server.respond(); assert.equals(this.postRootAsync.respond.args[0], [200, {}, "All POSTs"]); assert.equals(this.postPathAsync.respond.args[0], [200, {}, "Particular POST"]); } }, ".respondWith (FunctionHandler)": { setUp: function () { this.server = sinon.fakeServer.create(); }, tearDown: function () { this.server.restore(); }, "yields response to request function handler": function () { var handler = sinon.spy(); this.server.respondWith("/hello", handler); var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/hello"); xhr.send(); this.server.respond(); assert(handler.calledOnce); assert(handler.calledWith(xhr)); }, "responds to request from function handler": function () { this.server.respondWith("/hello", function (xhr) { xhr.respond(200, { "Content-Type": "application/json" }, "{\"id\":42}"); }); var request = new sinon.FakeXMLHttpRequest(); request.open("GET", "/hello"); request.send(); this.server.respond(); assert.equals(request.status, 200); assert.equals(request.responseHeaders, { "Content-Type": "application/json" }); assert.equals(request.responseText, "{\"id\":42}"); }, "yields response to request function handler when method matches": function () { var handler = sinon.spy(); this.server.respondWith("GET", "/hello", handler); var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/hello"); xhr.send(); this.server.respond(); assert(handler.calledOnce); }, "yields response to request function handler when url contains RegExp characters": function () { var handler = sinon.spy(); this.server.respondWith("GET", "/hello?world", handler); var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/hello?world"); xhr.send(); this.server.respond(); assert(handler.calledOnce); }, "does not yield response to request function handler when method does not match": function () { var handler = sinon.spy(); this.server.respondWith("GET", "/hello", handler); var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("POST", "/hello"); xhr.send(); this.server.respond(); assert(!handler.called); }, "yields response to request function handler when regexp url matches": function () { var handler = sinon.spy(); this.server.respondWith("GET", /\/.*/, handler); var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/hello"); xhr.send(); this.server.respond(); assert(handler.calledOnce); }, "does not yield response to request function handler when regexp url does not match": function () { var handler = sinon.spy(); this.server.respondWith("GET", /\/a.*/, handler); var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/hello"); xhr.send(); this.server.respond(); assert(!handler.called); }, "adds function handler without method or url filter": function () { this.server.respondWith(function (xhr) { xhr.respond(200, { "Content-Type": "application/json" }, "{\"id\":42}"); }); var request = new sinon.FakeXMLHttpRequest(); request.open("GET", "/whatever"); request.send(); this.server.respond(); assert.equals(request.status, 200); assert.equals(request.responseHeaders, { "Content-Type": "application/json" }); assert.equals(request.responseText, "{\"id\":42}"); }, "does not process request further if processed by function": function () { var handler = sinon.spy(); this.server.respondWith("GET", "/aloha", [200, {}, "Oh hi"]); this.server.respondWith("GET", /\/a.*/, handler); var xhr = new sinon.FakeXMLHttpRequest(); xhr.respond = sinon.spy(); xhr.open("GET", "/aloha"); xhr.send(); this.server.respond(); assert(handler.called); assert(xhr.respond.calledOnce); }, "yields URL capture groups to response handler": function () { var handler = sinon.spy(); this.server.respondWith("GET", /\/people\/(\d+)/, handler); var xhr = new sinon.FakeXMLHttpRequest(); xhr.respond = sinon.spy(); xhr.open("GET", "/people/3"); xhr.send(); this.server.respond(); assert(handler.called); assert.equals(handler.args[0], [xhr, "3"]); } }, "respond with fake HTTP Verb": { setUp: function () { this.server = sinon.fakeServer.create(); this.request = new sinon.FakeXMLHttpRequest(); this.request.open("post", "/path", true); this.request.send("_method=delete"); sinon.spy(this.request, "respond"); }, tearDown: function () { this.server.restore(); }, "does not respond to DELETE request with _method parameter": function () { this.server.respondWith("DELETE", "", ""); this.server.respond(); assert.equals(this.request.respond.args[0], [404, {}, ""]); }, "responds to 'fake' DELETE request": function () { this.server.fakeHTTPMethods = true; this.server.respondWith("DELETE", "", "OK"); this.server.respond(); assert.equals(this.request.respond.args[0], [200, {}, "OK"]); }, "does not respond to POST when faking DELETE": function () { this.server.fakeHTTPMethods = true; this.server.respondWith("POST", "", "OK"); this.server.respond(); assert.equals(this.request.respond.args[0], [404, {}, ""]); }, "does not fake method when not POSTing": function () { this.server.fakeHTTPMethods = true; this.server.respondWith("DELETE", "", "OK"); var request = new sinon.FakeXMLHttpRequest(); request.open("GET", "/"); request.send(); request.respond = sinon.spy(); this.server.respond(); assert.equals(request.respond.args[0], [404, {}, ""]); }, "customizes HTTP method extraction": function () { this.server.getHTTPMethod = function () { return "PUT"; }; this.server.respondWith("PUT", "", "OK"); this.server.respond(); assert.equals(this.request.respond.args[0], [200, {}, "OK"]); }, "does not fail when getting the HTTP method from a request with no body": function () { var server = this.server; server.fakeHTTPMethods = true; assert.equals(server.getHTTPMethod({ method: "POST" }), "POST"); } }, ".autoResponse": { setUp: function () { this.get = function get(url) { var request = new sinon.FakeXMLHttpRequest(); sinon.spy(request, "respond"); request.open("get", url, true); request.send(); return request; }; this.server = sinon.fakeServer.create(); this.clock = sinon.useFakeTimers(); }, tearDown: function () { this.server.restore(); this.clock.restore(); }, "responds async automatically after 10ms": function () { this.server.autoRespond = true; var request = this.get("/path"); this.clock.tick(10); assert.isTrue(request.respond.calledOnce); }, "normal server does not respond automatically": function () { var request = this.get("/path"); this.clock.tick(100); assert.isTrue(!request.respond.called); }, "auto-responds only once": function () { this.server.autoRespond = true; var requests = [this.get("/path")]; this.clock.tick(5); requests.push(this.get("/other")); this.clock.tick(5); assert.isTrue(requests[0].respond.calledOnce); assert.isTrue(requests[1].respond.calledOnce); }, "auto-responds after having already responded": function () { this.server.autoRespond = true; var requests = [this.get("/path")]; this.clock.tick(10); requests.push(this.get("/other")); this.clock.tick(10); assert.isTrue(requests[0].respond.calledOnce); assert.isTrue(requests[1].respond.calledOnce); }, "sets auto-respond timeout to 50ms": function () { this.server.autoRespond = true; this.server.autoRespondAfter = 50; var request = this.get("/path"); this.clock.tick(49); assert.isFalse(request.respond.called); this.clock.tick(1); assert.isTrue(request.respond.calledOnce); }, "auto-responds if two successive requests are made with a single XHR": function () { this.server.autoRespond = true; var request = this.get("/path"); this.clock.tick(10); assert.isTrue(request.respond.calledOnce); request.open("get", "/other", true); request.send(); this.clock.tick(10); assert.isTrue(request.respond.calledTwice); }, "auto-responds if timeout elapses between creating XHR object and sending request with it": function () { this.server.autoRespond = true; var request = new sinon.FakeXMLHttpRequest(); sinon.spy(request, "respond"); this.clock.tick(100); request.open("get", "/path", true); request.send(); this.clock.tick(10); assert.isTrue(request.respond.calledOnce); } }, ".respondImmediately": { setUp: function () { this.get = function get(url) { var request = new sinon.FakeXMLHttpRequest(); sinon.spy(request, "respond"); request.open("get", url, true); request.send(); return request; }; this.server = sinon.fakeServer.create(); this.server.respondImmediately = true; }, tearDown: function () { this.server.restore(); }, "responds synchronously": function () { var request = this.get("/path"); assert.isTrue(request.respond.calledOnce); }, "doesn't rely on a clock": function () { this.clock = sinon.useFakeTimers(); var request = this.get("/path"); assert.isTrue(request.respond.calledOnce); this.clock.restore(); } }, ".log": { setUp: function () { this.server = sinon.fakeServer.create(); }, tearDown: function () { this.server.restore(); }, "logs response and request": function () { sinon.spy(this.server, "log"); var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/hello"); xhr.send(); var response = [200, {}, "Hello!"]; this.server.respond("GET", /.*/, response); assert(this.server.log.calledOnce); assert(this.server.log.calledWithExactly(response, xhr)); }, "can be overridden": function () { this.server.log = sinon.spy(); var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/hello"); xhr.send(); var response = [200, {}, "Hello!"]; this.server.respond("GET", /.*/, response); assert(this.server.log.calledOnce); assert(this.server.log.calledWithExactly(response, xhr)); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/util/fake-server-with-clock-test.js000066400000000000000000000165541276775511300276470ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../../lib/sinon"); var assert = buster.assert; var refute = buster.refute; buster.testCase("sinon.fakeServerWithClock", { requiresSupportFor: { "browser": typeof window !== "undefined" }, "without pre-existing fake clock": { setUp: function () { this.server = sinon.fakeServerWithClock.create(); }, tearDown: function () { this.server.restore(); if (this.clock) { this.clock.restore(); } }, "calls 'super' when adding requests": sinon.test(function () { var addRequest = this.stub(sinon.fakeServer, "addRequest"); var xhr = {}; this.server.addRequest(xhr); assert(addRequest.calledWith(xhr)); assert(addRequest.calledOn(this.server)); }), "sets reference to clock when adding async request": function () { this.server.addRequest({ async: true }); assert.isObject(this.server.clock); assert.isFunction(this.server.clock.tick); }, "sets longest timeout from setTimeout": function () { this.server.addRequest({ async: true }); setTimeout(function () {}, 12); setTimeout(function () {}, 29); setInterval(function () {}, 12); setTimeout(function () {}, 27); assert.equals(this.server.longestTimeout, 29); }, "sets longest timeout from setInterval": function () { this.server.addRequest({ async: true }); setTimeout(function () {}, 12); setTimeout(function () {}, 29); setInterval(function () {}, 132); setTimeout(function () {}, 27); assert.equals(this.server.longestTimeout, 132); }, "resets clock": function () { this.server.addRequest({ async: true }); this.server.respond(""); assert.same(setTimeout, sinon.timers.setTimeout); }, "does not reset clock second time": function () { this.server.addRequest({ async: true }); this.server.respond(""); this.clock = sinon.useFakeTimers(); this.server.addRequest({ async: true }); this.server.respond(""); refute.same(setTimeout, sinon.timers.setTimeout); } }, "existing clock": { setUp: function () { this.clock = sinon.useFakeTimers(); this.server = sinon.fakeServerWithClock.create(); }, tearDown: function () { this.clock.restore(); this.server.restore(); }, "uses existing clock": function () { this.server.addRequest({ async: true }); assert.same(this.server.clock, this.clock); }, "records longest timeout using setTimeout and existing clock": function () { this.server.addRequest({ async: true }); setInterval(function () {}, 42); setTimeout(function () {}, 23); setTimeout(function () {}, 53); setInterval(function () {}, 12); assert.same(this.server.longestTimeout, 53); }, "records longest timeout using setInterval and existing clock": function () { this.server.addRequest({ async: true }); setInterval(function () {}, 92); setTimeout(function () {}, 73); setTimeout(function () {}, 53); setInterval(function () {}, 12); assert.same(this.server.longestTimeout, 92); }, "does not reset clock": function () { this.server.respond(""); assert.same(setTimeout.clock, this.clock); } }, ".respond": { setUp: function () { this.server = sinon.fakeServerWithClock.create(); this.server.addRequest({ async: true }); }, tearDown: function () { this.server.restore(); }, "ticks the clock to fire the longest timeout": function () { this.server.longestTimeout = 96; this.server.respond(); assert.equals(this.server.clock.now, 96); }, "ticks the clock to fire the longest timeout when multiple responds": function () { setInterval(function () {}, 13); this.server.respond(); var xhr = new sinon.FakeXMLHttpRequest(); // please the linter, we can't have unused variables // even when we're instantiating FakeXMLHttpRequest for it's side effects assert(xhr); setInterval(function () {}, 17); this.server.respond(); assert.equals(this.server.clock.now, 17); }, "resets longest timeout": function () { this.server.longestTimeout = 96; this.server.respond(); assert.equals(this.server.longestTimeout, 0); }, "calls original respond": function () { var obj = {}; var respond = this.stub(sinon.fakeServer, "respond").returns(obj); var result = this.server.respond("GET", "/", ""); assert.equals(result, obj); assert(respond.calledWith("GET", "/", "")); assert(respond.calledOn(this.server)); } }, "jQuery compat mode": { setUp: function () { this.server = sinon.fakeServerWithClock.create(); this.request = new sinon.FakeXMLHttpRequest(); this.request.open("get", "/", true); this.request.send(); sinon.spy(this.request, "respond"); }, tearDown: function () { this.server.restore(); }, "handles clock automatically": function () { this.server.respondWith("OK"); var spy = sinon.spy(); setTimeout(spy, 13); this.server.respond(); this.server.restore(); assert(spy.called); assert.same(setTimeout, sinon.timers.setTimeout); }, "finishes xhr from setInterval like jQuery 1.3.x does": function () { this.server.respondWith("Hello World"); var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/"); xhr.send(); var spy = sinon.spy(); setInterval(function () { spy(xhr.responseText, xhr.statusText, xhr); }, 13); this.server.respond(); assert.equals(spy.args[0][0], "Hello World"); assert.equals(spy.args[0][1], "OK"); assert.equals(spy.args[0][2].status, 200); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/util/fake-timers-test.js000066400000000000000000001075621276775511300256020ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../../lib/sinon"); var assert = buster.assert; var refute = buster.refute; var GlobalDate = Date; buster.testCase("sinon.clock", { setUp: function () { this.global = typeof global !== "undefined" ? global : window; }, ".setTimeout": { setUp: function () { this.clock = sinon.clock.create(); this.global.sinonClockEvalCalled = false; }, tearDown: function () { delete this.global.sinonClockEvalCalled; }, "throws if no arguments": function () { var clock = this.clock; assert.exception(function () { clock.setTimeout(); }); }, "returns numeric id or object with numeric id": function () { var result = this.clock.setTimeout(""); if (typeof result === "object") { assert.isNumber(result.id); } else { assert.isNumber(result); } }, "returns unique id": function () { var id1 = this.clock.setTimeout(""); var id2 = this.clock.setTimeout(""); refute.equals(id2, id1); }, "sets timers on instance": function () { var clock1 = sinon.clock.create(); var clock2 = sinon.clock.create(); var stubs = [sinon.stub.create(), sinon.stub.create()]; clock1.setTimeout(stubs[0], 100); clock2.setTimeout(stubs[1], 100); clock2.tick(200); assert.isFalse(stubs[0].called); assert(stubs[1].called); }, "evals non-function callbacks": function () { var evalCalledString = (typeof global !== "undefined" ? "global" : "window") + ".sinonClockEvalCalled = true"; this.clock.setTimeout(evalCalledString, 10); this.clock.tick(10); assert(this.global.sinonClockEvalCalled); }, "passes setTimeout parameters": function () { var clock = sinon.clock.create(); var stub = sinon.stub.create(); clock.setTimeout(stub, 2, "the first", "the second"); clock.tick(3); assert.isTrue(stub.calledWithExactly("the first", "the second")); }, "calls correct timeout on recursive tick": function () { var clock = sinon.clock.create(); var stub = sinon.stub.create(); var recurseCallback = function () { clock.tick(100); }; clock.setTimeout(recurseCallback, 50); clock.setTimeout(stub, 100); clock.tick(50); assert(stub.called); } }, ".setImmediate": { setUp: function () { this.clock = sinon.clock.create(); }, "returns numeric id or object with numeric id": function () { var result = this.clock.setImmediate(function () { }); if (typeof result === "object") { assert.isNumber(result.id); } else { assert.isNumber(result); } }, "calls the given callback immediately": function () { var stub = sinon.stub.create(); this.clock.setImmediate(stub); this.clock.tick(0); assert(stub.called); }, "throws if no arguments": function () { var clock = this.clock; assert.exception(function () { clock.setImmediate(); }); }, "manages separate timers per clock instance": function () { var clock1 = sinon.clock.create(); var clock2 = sinon.clock.create(); var stubs = [sinon.stub.create(), sinon.stub.create()]; clock1.setImmediate(stubs[0]); clock2.setImmediate(stubs[1]); clock2.tick(0); assert.isFalse(stubs[0].called); assert(stubs[1].called); }, "passes extra parameters through to the callback": function () { var stub = sinon.stub.create(); this.clock.setImmediate(stub, "value1", 2); this.clock.tick(1); assert(stub.calledWithExactly("value1", 2)); } }, ".clearImmediate": { setUp: function () { this.clock = sinon.clock.create(); }, "removes immediate callbacks": function () { var callback = sinon.stub.create(); var id = this.clock.setImmediate(callback); this.clock.clearImmediate(id); this.clock.tick(1); assert.isFalse(callback.called); } }, ".tick": { setUp: function () { this.clock = sinon.useFakeTimers(0); }, tearDown: function () { this.clock.restore(); }, "triggers immediately without specified delay": function () { var stub = sinon.stub.create(); this.clock.setTimeout(stub); this.clock.tick(0); assert(stub.called); }, "does not trigger without sufficient delay": function () { var stub = sinon.stub.create(); this.clock.setTimeout(stub, 100); this.clock.tick(10); assert.isFalse(stub.called); }, "triggers after sufficient delay": function () { var stub = sinon.stub.create(); this.clock.setTimeout(stub, 100); this.clock.tick(100); assert(stub.called); }, "triggers simultaneous timers": function () { var spies = [sinon.spy(), sinon.spy()]; this.clock.setTimeout(spies[0], 100); this.clock.setTimeout(spies[1], 100); this.clock.tick(100); assert(spies[0].called); assert(spies[1].called); }, "triggers multiple simultaneous timers": function () { var spies = [sinon.spy(), sinon.spy(), sinon.spy(), sinon.spy()]; this.clock.setTimeout(spies[0], 100); this.clock.setTimeout(spies[1], 100); this.clock.setTimeout(spies[2], 99); this.clock.setTimeout(spies[3], 100); this.clock.tick(100); assert(spies[0].called); assert(spies[1].called); assert(spies[2].called); assert(spies[3].called); }, "triggers multiple simultaneous timers with zero callAt": function () { var test = this; var spies = [ sinon.spy(function () { test.clock.setTimeout(spies[1], 0); }), sinon.spy(), sinon.spy() ]; // First spy calls another setTimeout with delay=0 this.clock.setTimeout(spies[0], 0); this.clock.setTimeout(spies[2], 10); this.clock.tick(10); assert(spies[0].called); assert(spies[1].called); assert(spies[2].called); }, "waits after setTimeout was called": function () { this.clock.tick(100); var stub = sinon.stub.create(); this.clock.setTimeout(stub, 150); this.clock.tick(50); assert.isFalse(stub.called); this.clock.tick(100); assert(stub.called); }, "mini integration test": function () { var stubs = [sinon.stub.create(), sinon.stub.create(), sinon.stub.create()]; this.clock.setTimeout(stubs[0], 100); this.clock.setTimeout(stubs[1], 120); this.clock.tick(10); this.clock.tick(89); assert.isFalse(stubs[0].called); assert.isFalse(stubs[1].called); this.clock.setTimeout(stubs[2], 20); this.clock.tick(1); assert(stubs[0].called); assert.isFalse(stubs[1].called); assert.isFalse(stubs[2].called); this.clock.tick(19); assert.isFalse(stubs[1].called); assert(stubs[2].called); this.clock.tick(1); assert(stubs[1].called); }, "triggers even when some throw": function () { var clock = this.clock; var stubs = [sinon.stub.create().throws(), sinon.stub.create()]; clock.setTimeout(stubs[0], 100); clock.setTimeout(stubs[1], 120); assert.exception(function () { clock.tick(120); }); assert(stubs[0].called); assert(stubs[1].called); }, "calls function with global object or null (strict mode) as this": function () { var clock = this.clock; var stub = sinon.stub.create().throws(); clock.setTimeout(stub, 100); assert.exception(function () { clock.tick(100); }); assert(stub.calledOn(this.global) || stub.calledOn(null)); }, "triggers in the order scheduled": function () { var spies = [sinon.spy.create(), sinon.spy.create()]; this.clock.setTimeout(spies[0], 13); this.clock.setTimeout(spies[1], 11); this.clock.tick(15); assert(spies[1].calledBefore(spies[0])); }, "creates updated Date while ticking": function () { var spy = sinon.spy.create(); this.clock.setInterval(function () { spy(new Date().getTime()); }, 10); this.clock.tick(100); assert.equals(spy.callCount, 10); assert(spy.calledWith(10)); assert(spy.calledWith(20)); assert(spy.calledWith(30)); assert(spy.calledWith(40)); assert(spy.calledWith(50)); assert(spy.calledWith(60)); assert(spy.calledWith(70)); assert(spy.calledWith(80)); assert(spy.calledWith(90)); assert(spy.calledWith(100)); }, "fires timer in intervals of 13": function () { var spy = sinon.spy.create(); this.clock.setInterval(spy, 13); this.clock.tick(500); assert.equals(spy.callCount, 38); }, "fires timers in correct order": function () { var spy13 = sinon.spy.create(); var spy10 = sinon.spy.create(); this.clock.setInterval(function () { spy13(new Date().getTime()); }, 13); this.clock.setInterval(function () { spy10(new Date().getTime()); }, 10); this.clock.tick(500); assert.equals(spy13.callCount, 38); assert.equals(spy10.callCount, 50); assert(spy13.calledWith(416)); assert(spy10.calledWith(320)); assert(spy10.getCall(0).calledBefore(spy13.getCall(0))); assert(spy10.getCall(4).calledBefore(spy13.getCall(3))); }, "triggers timeouts and intervals in the order scheduled": function () { var spies = [sinon.spy.create(), sinon.spy.create()]; this.clock.setInterval(spies[0], 10); this.clock.setTimeout(spies[1], 50); this.clock.tick(100); assert(spies[0].calledBefore(spies[1])); assert.equals(spies[0].callCount, 10); assert.equals(spies[1].callCount, 1); }, "does not fire canceled intervals": function () { var id; var callback = sinon.spy(function () { if (callback.callCount === 3) { clearInterval(id); } }); id = this.clock.setInterval(callback, 10); this.clock.tick(100); assert.equals(callback.callCount, 3); }, "passes 6 seconds": function () { var spy = sinon.spy.create(); this.clock.setInterval(spy, 4000); this.clock.tick("08"); assert.equals(spy.callCount, 2); }, "passes 1 minute": function () { var spy = sinon.spy.create(); this.clock.setInterval(spy, 6000); this.clock.tick("01:00"); assert.equals(spy.callCount, 10); }, "passes 2 hours, 34 minutes and 12 seconds": function () { var spy = sinon.spy.create(); this.clock.setInterval(spy, 10000); this.clock.tick("02:34:10"); assert.equals(spy.callCount, 925); }, "throws for invalid format": function () { var spy = sinon.spy.create(); this.clock.setInterval(spy, 10000); var test = this; assert.exception(function () { test.clock.tick("12:02:34:10"); }); assert.equals(spy.callCount, 0); }, "throws for invalid minutes": function () { var spy = sinon.spy.create(); this.clock.setInterval(spy, 10000); var test = this; assert.exception(function () { test.clock.tick("67:10"); }); assert.equals(spy.callCount, 0); }, "throws for negative minutes": function () { var spy = sinon.spy.create(); this.clock.setInterval(spy, 10000); var test = this; assert.exception(function () { test.clock.tick("-7:10"); }); assert.equals(spy.callCount, 0); }, "treats missing argument as 0": function () { this.clock.tick(); assert.equals(this.clock.now, 0); }, "fires nested setTimeout calls properly": function () { var i = 0; var clock = this.clock; var callback = function () { ++i; clock.setTimeout(function () { callback(); }, 100); }; callback(); clock.tick(1000); assert.equals(i, 11); }, "does not silently catch exceptions": function () { var clock = this.clock; clock.setTimeout(function () { throw new Error("oh no!"); }, 1000); assert.exception(function () { clock.tick(1000); }); }, "returns the current now value": function () { var clock = this.clock; var value = clock.tick(200); assert.equals(clock.now, value); } }, ".clearTimeout": { setUp: function () { this.clock = sinon.clock.create(); }, "removes timeout": function () { var stub = sinon.stub.create(); var id = this.clock.setTimeout(stub, 50); this.clock.clearTimeout(id); this.clock.tick(50); assert.isFalse(stub.called); }, "ignores null argument": function () { this.clock.clearTimeout(null); assert(true); // doesn't fail } }, ".reset": { setUp: function () { this.clock = sinon.clock.create(); }, "empties timeouts queue": function () { var stub = sinon.stub.create(); this.clock.setTimeout(stub); this.clock.reset(); this.clock.tick(0); assert.isFalse(stub.called); } }, ".setInterval": { setUp: function () { this.clock = sinon.clock.create(); }, "throws if no arguments": function () { var clock = this.clock; assert.exception(function () { clock.setInterval(); }); }, "returns numeric id or object with numeric id": function () { var result = this.clock.setInterval(""); if (typeof result === "object") { assert.isNumber(result.id); } else { assert.isNumber(result); } }, "returns unique id": function () { var id1 = this.clock.setInterval(""); var id2 = this.clock.setInterval(""); refute.equals(id2, id1); }, "schedules recurring timeout": function () { var stub = sinon.stub.create(); this.clock.setInterval(stub, 10); this.clock.tick(99); assert.equals(stub.callCount, 9); }, "does not schedule recurring timeout when cleared": function () { var clock = this.clock; var id; var stub = sinon.spy.create(function () { if (stub.callCount === 3) { clock.clearInterval(id); } }); id = this.clock.setInterval(stub, 10); this.clock.tick(100); assert.equals(stub.callCount, 3); }, "passes setTimeout parameters": function () { var clock = sinon.clock.create(); var stub = sinon.stub.create(); clock.setInterval(stub, 2, "the first", "the second"); clock.tick(3); assert.isTrue(stub.calledWithExactly("the first", "the second")); } }, ".date": { setUp: function () { this.now = new GlobalDate().getTime() - 3000; this.clock = sinon.clock.create(this.now); this.Date = this.global.Date; }, tearDown: function () { this.global.Date = this.Date; }, "provides date constructor": function () { assert.isFunction(this.clock.Date); }, "creates real Date objects": function () { var date = new this.clock.Date(); assert(Date.prototype.isPrototypeOf(date)); }, "creates real Date objects when called as function": function () { var date = this.clock.Date(); assert(Date.prototype.isPrototypeOf(date)); }, "creates real Date objects when Date constructor is gone": function () { var realDate = new Date(); Date = function () {}; // eslint-disable-line no-undef, no-native-reassign this.global.Date = function () {}; var date = new this.clock.Date(); assert.same(date.constructor.prototype, realDate.constructor.prototype); }, "creates Date objects representing clock time": function () { var date = new this.clock.Date(); assert.equals(date.getTime(), new Date(this.now).getTime()); }, "returns Date object representing clock time": function () { var date = this.clock.Date(); assert.equals(date.getTime(), new Date(this.now).getTime()); }, "listens to ticking clock": function () { var date1 = new this.clock.Date(); this.clock.tick(3); var date2 = new this.clock.Date(); assert.equals(date2.getTime() - date1.getTime(), 3); }, "creates regular date when passing timestamp": function () { var date = new Date(); var fakeDate = new this.clock.Date(date.getTime()); assert.equals(fakeDate.getTime(), date.getTime()); }, "returns regular date when calling with timestamp": function () { var date = new Date(); var fakeDate = this.clock.Date(date.getTime()); assert.equals(fakeDate.getTime(), date.getTime()); }, "creates regular date when passing year, month": function () { var date = new Date(2010, 4); var fakeDate = new this.clock.Date(2010, 4); assert.equals(fakeDate.getTime(), date.getTime()); }, "returns regular date when calling with year, month": function () { var date = new Date(2010, 4); var fakeDate = this.clock.Date(2010, 4); assert.equals(fakeDate.getTime(), date.getTime()); }, "creates regular date when passing y, m, d": function () { var date = new Date(2010, 4, 2); var fakeDate = new this.clock.Date(2010, 4, 2); assert.equals(fakeDate.getTime(), date.getTime()); }, "returns regular date when calling with y, m, d": function () { var date = new Date(2010, 4, 2); var fakeDate = this.clock.Date(2010, 4, 2); assert.equals(fakeDate.getTime(), date.getTime()); }, "creates regular date when passing y, m, d, h": function () { var date = new Date(2010, 4, 2, 12); var fakeDate = new this.clock.Date(2010, 4, 2, 12); assert.equals(fakeDate.getTime(), date.getTime()); }, "returns regular date when calling with y, m, d, h": function () { var date = new Date(2010, 4, 2, 12); var fakeDate = this.clock.Date(2010, 4, 2, 12); assert.equals(fakeDate.getTime(), date.getTime()); }, "creates regular date when passing y, m, d, h, m": function () { var date = new Date(2010, 4, 2, 12, 42); var fakeDate = new this.clock.Date(2010, 4, 2, 12, 42); assert.equals(fakeDate.getTime(), date.getTime()); }, "returns regular date when calling with y, m, d, h, m": function () { var date = new Date(2010, 4, 2, 12, 42); var fakeDate = this.clock.Date(2010, 4, 2, 12, 42); assert.equals(fakeDate.getTime(), date.getTime()); }, "creates regular date when passing y, m, d, h, m, s": function () { var date = new Date(2010, 4, 2, 12, 42, 53); var fakeDate = new this.clock.Date(2010, 4, 2, 12, 42, 53); assert.equals(fakeDate.getTime(), date.getTime()); }, "returns regular date when calling with y, m, d, h, m, s": function () { var date = new Date(2010, 4, 2, 12, 42, 53); var fakeDate = this.clock.Date(2010, 4, 2, 12, 42, 53); assert.equals(fakeDate.getTime(), date.getTime()); }, "creates regular date when passing y, m, d, h, m, s, ms": function () { var date = new Date(2010, 4, 2, 12, 42, 53, 498); var fakeDate = new this.clock.Date(2010, 4, 2, 12, 42, 53, 498); assert.equals(fakeDate.getTime(), date.getTime()); }, "returns regular date when calling with y, m, d, h, m, s, ms": function () { var date = new Date(2010, 4, 2, 12, 42, 53, 498); var fakeDate = this.clock.Date(2010, 4, 2, 12, 42, 53, 498); assert.equals(fakeDate.getTime(), date.getTime()); }, "mirrors native Date.prototype": function () { assert.same(this.clock.Date.prototype, Date.prototype); }, "supports now method if present": function () { assert.same(typeof this.clock.Date.now, typeof Date.now); }, ".now": { requiresSupportFor: { "Date.now": !!Date.now }, "returns clock.now": function () { assert.equals(this.clock.Date.now(), this.now); } }, "unsupported now": { requiresSupportFor: { "No Date.now implementation": !Date.now }, "is undefined": function () { refute.defined(this.clock.Date.now); } }, "mirrors parse method": function () { assert.same(this.clock.Date.parse, Date.parse); }, "mirrors UTC method": function () { assert.same(this.clock.Date.UTC, Date.UTC); }, "mirrors toUTCString method": function () { assert.same(this.clock.Date.prototype.toUTCString, Date.prototype.toUTCString); }, ".toSource": { requiresSupportFor: { "Date.toSource": !!Date.toSource }, "is mirrored": function () { assert.same(this.clock.Date.toSource(), Date.toSource()); } }, "unsupported toSource": { requiresSupportFor: { "No Date.toSource implementation": !Date.toSource }, "is undefined": function () { refute.defined(this.clock.Date.toSource); } }, "mirrors toString": function () { assert.same(this.clock.Date.toString(), Date.toString()); } }, ".useFakeTimers": { setUp: function () { this.dateNow = this.global.Date.now; this.original = { Date: this.global.Date, setTimeout: this.global.setTimeout, clearTimeout: this.global.clearTimeout, setInterval: this.global.setInterval, clearInterval: this.global.clearInterval, setImmediate: this.global.setImmediate, clearImmediate: this.global.clearImmediate }; }, tearDown: function () { this.global.Date = this.original.Date; this.global.setTimeout = this.original.setTimeout; this.global.clearTimeout = this.original.clearTimeout; this.global.setInterval = this.original.setInterval; this.global.clearInterval = this.original.clearInterval; this.global.setImmediate = this.original.setImmediate; this.global.clearImmediate = this.original.clearImmediate; clearTimeout(this.timer); if (typeof this.dateNow === "undefined") { delete this.global.Date.now; } else { this.global.Date.now = this.dateNow; } }, "returns clock object": function () { this.clock = sinon.useFakeTimers(); assert.isObject(this.clock); assert.isFunction(this.clock.tick); }, "has clock property": function () { this.clock = sinon.useFakeTimers(); assert.same(setTimeout.clock, this.clock); assert.same(clearTimeout.clock, this.clock); assert.same(setInterval.clock, this.clock); assert.same(clearInterval.clock, this.clock); assert.same(Date.clock, this.clock); }, "sets initial timestamp": function () { this.clock = sinon.useFakeTimers(1400); assert.equals(this.clock.now, 1400); }, "replaces global setTimeout": function () { this.clock = sinon.useFakeTimers(); var stub = sinon.stub.create(); setTimeout(stub, 1000); this.clock.tick(1000); assert(stub.called); }, "global fake setTimeout should return id": function () { this.clock = sinon.useFakeTimers(); var stub = sinon.stub.create(); var to = setTimeout(stub, 1000); if (typeof (setTimeout(function () {}, 0)) === "object") { assert.isNumber(to.id); assert.isFunction(to.ref); assert.isFunction(to.unref); } else { assert.isNumber(to); } }, "replaces global clearTimeout": function () { this.clock = sinon.useFakeTimers(); var stub = sinon.stub.create(); clearTimeout(setTimeout(stub, 1000)); this.clock.tick(1000); assert.isFalse(stub.called); }, "restores global setTimeout": function () { this.clock = sinon.useFakeTimers(); var stub = sinon.stub.create(); this.clock.restore(); this.timer = setTimeout(stub, 1000); this.clock.tick(1000); assert.isFalse(stub.called); assert.same(setTimeout, sinon.timers.setTimeout); }, "restores global clearTimeout": function () { this.clock = sinon.useFakeTimers(); sinon.stub.create(); this.clock.restore(); assert.same(clearTimeout, sinon.timers.clearTimeout); }, "replaces global setInterval": function () { this.clock = sinon.useFakeTimers(); var stub = sinon.stub.create(); setInterval(stub, 500); this.clock.tick(1000); assert(stub.calledTwice); }, "replaces global clearInterval": function () { this.clock = sinon.useFakeTimers(); var stub = sinon.stub.create(); clearInterval(setInterval(stub, 500)); this.clock.tick(1000); assert.isFalse(stub.called); }, "restores global setInterval": function () { this.clock = sinon.useFakeTimers(); var stub = sinon.stub.create(); this.clock.restore(); this.timer = setInterval(stub, 1000); this.clock.tick(1000); assert.isFalse(stub.called); assert.same(setInterval, sinon.timers.setInterval); }, "restores global clearInterval": function () { this.clock = sinon.useFakeTimers(); sinon.stub.create(); this.clock.restore(); assert.same(clearInterval, sinon.timers.clearInterval); }, "deletes global property on restore if it was inherited onto the global object": function () { // Give the global object an inherited 'tick' method delete this.global.tick; /*eslint-disable no-proto*/ this.global.__proto__.tick = function () { }; if (!this.global.hasOwnProperty("tick")) { this.clock = sinon.useFakeTimers("tick"); assert.isTrue(this.global.hasOwnProperty("tick")); this.clock.restore(); assert.isFalse(this.global.hasOwnProperty("tick")); delete this.global.__proto__.tick; } else { // hasOwnProperty does not work as expected. assert(true); } /*eslint-enable no-proto*/ }, "restores global property on restore if it is present on the global object itself": function () { // Directly give the global object a tick method this.global.tick = function () { }; this.clock = sinon.useFakeTimers("tick"); assert.isTrue(this.global.hasOwnProperty("tick")); this.clock.restore(); assert.isTrue(this.global.hasOwnProperty("tick")); delete this.global.tick; }, "fakes Date constructor": function () { this.clock = sinon.useFakeTimers(0); var now = new Date(); refute.same(Date, sinon.timers.Date); assert.equals(now.getTime(), 0); }, "fake Date constructor should mirror Date's properties": function () { this.clock = sinon.useFakeTimers(0); assert(!!Date.parse); assert(!!Date.UTC); }, "decide on Date.now support at call-time when supported": function () { this.global.Date.now = function () {}; this.clock = sinon.useFakeTimers(0); assert.equals(typeof Date.now, "function"); }, "decide on Date.now support at call-time when unsupported": function () { this.global.Date.now = null; this.clock = sinon.useFakeTimers(0); refute.defined(Date.now); }, "mirrors custom Date properties": function () { var f = function () { }; this.global.Date.format = f; sinon.useFakeTimers(); assert.equals(Date.format, f); }, "restores Date constructor": function () { this.clock = sinon.useFakeTimers(0); this.clock.restore(); assert.same(GlobalDate, sinon.timers.Date); }, "fakes provided methods": function () { this.clock = sinon.useFakeTimers("setTimeout", "Date", "setImmediate"); refute.same(setTimeout, sinon.timers.setTimeout); refute.same(Date, sinon.timers.Date); refute.same(setImmediate, sinon.timers.setImmediate); }, "resets faked methods": function () { this.clock = sinon.useFakeTimers("setTimeout", "Date", "setImmediate"); this.clock.restore(); assert.same(setTimeout, sinon.timers.setTimeout); assert.same(Date, sinon.timers.Date); assert.same(setImmediate, sinon.timers.setImmediate); }, "does not fake methods not provided": function () { this.clock = sinon.useFakeTimers("setTimeout", "Date", "setImmediate"); assert.same(clearTimeout, sinon.timers.clearTimeout); assert.same(setInterval, sinon.timers.setInterval); assert.same(clearInterval, sinon.timers.clearInterval); }, "does not be able to use date object for now": function () { assert.exception(function () { sinon.useFakeTimers(new Date(2011, 9, 1)); }); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/util/fake-xdomain-request-test.js000066400000000000000000000346161276775511300274230ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../../lib/sinon"); var assert = buster.assert; var refute = buster.refute; var globalXDomainRequest = root.XDomainRequest; var fakeXdrSetUp = function () { this.fakeXdr = sinon.useFakeXDomainRequest(); }; var fakeXdrTearDown = function () { if (typeof this.fakeXdr.restore === "function") { this.fakeXdr.restore(); } }; buster.testCase("sinon.FakeXDomainRequest", { requiresSupportFor: { "browser": typeof window !== "undefined" }, "is constructor": function () { assert.isFunction(sinon.FakeXDomainRequest); assert.same(sinon.FakeXDomainRequest.prototype.constructor, sinon.FakeXDomainRequest); }, "implements readyState constants": function () { assert.same(sinon.FakeXDomainRequest.UNSENT, 0); assert.same(sinon.FakeXDomainRequest.OPENED, 1); assert.same(sinon.FakeXDomainRequest.LOADING, 3); assert.same(sinon.FakeXDomainRequest.DONE, 4); }, "calls onCreate if listener is set": function () { var onCreate = sinon.spy(); sinon.FakeXDomainRequest.onCreate = onCreate; var xhr = new sinon.FakeXDomainRequest(); // makes the linter happy assert(xhr); assert(onCreate.called); }, "passes new object to onCreate if set": function () { var onCreate = sinon.spy(); sinon.FakeXDomainRequest.onCreate = onCreate; var xhr = new sinon.FakeXDomainRequest(); assert.same(onCreate.getCall(0).args[0], xhr); }, ".open": { setUp: function () { this.xdr = new sinon.FakeXDomainRequest(); }, "is method": function () { assert.isFunction(this.xdr.open); }, "sets properties on object": function () { this.xdr.open("GET", "/my/url"); assert.equals(this.xdr.method, "GET"); assert.equals(this.xdr.url, "/my/url"); }, "sets responseText to null": function () { this.xdr.open("GET", "/my/url"); assert.isNull(this.xdr.responseText); }, "sets send flag to false": function () { this.xdr.open("GET", "/my/url"); assert.isFalse(this.xdr.sendFlag); }, "sets readyState to OPENED": function () { this.xdr.open("GET", "/my/url"); assert.same(this.xdr.readyState, sinon.FakeXDomainRequest.OPENED); }, "sets requestHeaders to blank object": function () { this.xdr.open("GET", "/my/url"); assert.isObject(this.xdr.requestHeaders); assert.equals(this.xdr.requestHeaders, {}); } }, ".send": { setUp: function () { this.xdr = new sinon.FakeXDomainRequest(); }, "throws if request is not open": function () { var xdr = new sinon.FakeXDomainRequest(); assert.exception(function () { xdr.send(); }); }, "throws if send flag is true": function () { var xdr = this.xdr; xdr.open("GET", "/"); xdr.sendFlag = true; assert.exception(function () { xdr.send(); }); }, "sets GET body to null": function () { this.xdr.open("GET", "/"); this.xdr.send("Data"); assert.isNull(this.xdr.requestBody); }, "sets HEAD body to null": function () { this.xdr.open("HEAD", "/"); this.xdr.send("Data"); assert.isNull(this.xdr.requestBody); }, "sets mime to text/plain for all methods": function () { var methods = ["GET", "HEAD", "POST"]; for (var i = 0; i < methods.length; i++) { this.xdr.open(methods[i], "/"); this.xdr.send("Data"); assert.equals(this.xdr.requestHeaders["Content-Type"], "text/plain;charset=utf-8"); } }, "sets request body to string data": function () { this.xdr.open("POST", "/"); this.xdr.send("Data"); assert.equals(this.xdr.requestBody, "Data"); }, "sets error flag to false": function () { this.xdr.open("POST", "/"); this.xdr.send("Data"); assert.isFalse(this.xdr.errorFlag); }, "sets send flag to true": function () { this.xdr.open("POST", "/"); this.xdr.send("Data"); assert.isTrue(this.xdr.sendFlag); }, "calls readyStateChange": function () { this.xdr.open("POST", "/", false); var spy = sinon.spy(); this.xdr.readyStateChange = spy; this.xdr.send("Data"); assert.equals(this.xdr.readyState, sinon.FakeXDomainRequest.OPENED); assert.isTrue(spy.called); } }, ".setResponseBody": { setUp: function () { this.xdr = new sinon.FakeXDomainRequest(); this.xdr.open("GET", "/"); this.xdr.send(); }, "invokes readyStateChange handler with LOADING state": function () { var spy = sinon.spy(); this.xdr.readyStateChange = spy; this.xdr.setResponseBody("Some text goes in here ok?"); assert(spy.calledWith(sinon.FakeXDomainRequest.LOADING)); }, "fire onprogress event": function () { var spy = sinon.spy(); this.xdr.onprogress = spy; this.xdr.setResponseBody("Some text goes in here ok?"); assert.isTrue(spy.called); }, "invokes readyStateChange handler for each 10 byte chunk": function () { var spy = sinon.spy(); this.xdr.readyStateChange = spy; this.xdr.chunkSize = 10; this.xdr.setResponseBody("Some text goes in here ok?"); assert.equals(spy.callCount, 4); }, "invokes readyStateChange handler for each x byte chunk": function () { var spy = sinon.spy(); this.xdr.readyStateChange = spy; this.xdr.chunkSize = 20; this.xdr.setResponseBody("Some text goes in here ok?"); assert.equals(spy.callCount, 3); }, "invokes readyStateChange handler with partial data": function () { var pieces = []; var spy = sinon.spy(function () { pieces.push(this.responseText); }); this.xdr.readyStateChange = spy; this.xdr.chunkSize = 9; this.xdr.setResponseBody("Some text goes in here ok?"); assert.equals(pieces[1], "Some text"); }, "calls readyStateChange with DONE state": function () { var spy = sinon.spy(); this.xdr.readyStateChange = spy; this.xdr.setResponseBody("Some text goes in here ok?"); assert(spy.calledWith(sinon.FakeXDomainRequest.DONE)); }, "throws if not open": function () { var xdr = new sinon.FakeXDomainRequest(); assert.exception(function () { xdr.setResponseBody(""); }); }, "throws if body was already sent": function () { var xdr = new sinon.FakeXDomainRequest(); xdr.open("GET", "/"); xdr.send(); xdr.setResponseBody(""); assert.exception(function () { xdr.setResponseBody(""); }); }, "throws if body is not a string": function () { var xdr = new sinon.FakeXDomainRequest(); xdr.open("GET", "/"); xdr.send(); assert.exception(function () { xdr.setResponseBody({}); }, "InvalidBodyException"); } }, ".respond": { setUp: function () { this.xdr = new sinon.FakeXDomainRequest(); this.xdr.open("GET", "/"); var spy = this.spy = sinon.spy(); this.xdr.onload = spy.call(this); this.xdr.send(); }, "fire onload event": function () { this.onload = this.spy; this.xdr.respond(200, {}, ""); assert.equals(this.spy.callCount, 1); }, "fire onload event with this set to the XHR object": function (done) { var xdr = new sinon.FakeXDomainRequest(); xdr.open("GET", "/"); xdr.onload = function () { assert.same(this, xdr); done(); }; xdr.send(); xdr.respond(200, {}, ""); }, "calls readystate handler with readyState DONE once": function () { this.xdr.respond(200, {}, ""); assert.equals(this.spy.callCount, 1); }, "defaults to status 200, no headers, and blank body": function () { this.xdr.respond(); assert.equals(this.xdr.status, 200); assert.equals(this.xdr.responseText, ""); }, "sets status": function () { this.xdr.respond(201); assert.equals(this.xdr.status, 201); } }, ".simulatetimeout": { setUp: function () { this.xdr = new sinon.FakeXDomainRequest(); this.xdr.open("GET", "/"); this.xdr.send(); this.xdr.timeout = 100; }, "fires ontimeout event": function () { var spy = sinon.spy(); this.xdr.ontimeout = spy; this.xdr.simulatetimeout(); assert.isTrue(this.xdr.isTimeout); assert.isTrue(spy.called); }, "readyState is DONE": function () { this.xdr.simulatetimeout(); assert.equals(this.xdr.readyState, sinon.FakeXDomainRequest.DONE); }, "ensures responseText is not accessible": function () { var spy = sinon.spy(); this.xdr.ontimeout = spy; this.xdr.simulatetimeout(); assert.isTrue(spy.called); refute.defined(this.xdr.responseText); } }, ".abort": { setUp: function () { this.xdr = new sinon.FakeXDomainRequest(); }, "sets aborted flag to true": function () { this.xdr.aborted = true; this.xdr.abort(); assert.isTrue(this.xdr.aborted); }, "sets responseText to null": function () { this.xdr.responseText = "Partial data"; this.xdr.abort(); assert.isNull(this.xdr.responseText); }, "sets errorFlag to true": function () { this.xdr.errorFlag = true; this.xdr.abort(); assert.isTrue(this.xdr.errorFlag); }, "fire onerror event": function () { var spy = sinon.spy(); this.xdr.onerror = spy; this.xdr.open("GET", "/"); this.xdr.send(); this.xdr.abort(); assert.equals(spy.callCount, 1); }, "sets state to DONE if sent before": function () { this.xdr.open("GET", "/"); this.xdr.send(); this.xdr.readyStateChange = sinon.spy(); this.xdr.abort(); assert(this.xdr.readyStateChange.calledWith(sinon.FakeXDomainRequest.DONE)); }, "sets send flag to false if sent before": function () { this.xdr.open("GET", "/"); this.xdr.send(); this.xdr.abort(); assert.isFalse(this.xdr.sendFlag); }, "does not dispatch readystatechange event if readyState is unsent": function () { this.xdr.readyStateChange = sinon.stub(); this.xdr.abort(); assert.isFalse(this.xdr.readyStateChange.called); }, "does not dispatch readystatechange event if readyState is opened but not sent": function () { this.xdr.open("GET", "/"); this.xdr.readyStateChange = sinon.stub(); this.xdr.abort(); assert.isFalse(this.xdr.readyStateChange.called); } }, "missing native XDR": { requiresSupportFor: { "no native XDR": typeof XDomainRequest === "undefined" }, setUp: fakeXdrSetUp, tearDown: fakeXdrTearDown, "does not expose XDomainRequest": function () { assert.equals(typeof XDomainRequest, "undefined"); }, "does not expose XDomainRequest after restore": function () { this.fakeXdr.restore(); assert.equals(typeof XDomainRequest, "undefined"); } }, "native XDR": { requiresSupportFor: { XDR: typeof XDomainRequest !== "undefined" }, setUp: fakeXdrSetUp, tearDown: fakeXdrTearDown, "replaces global XDomainRequest": function () { refute.same(XDomainRequest, globalXDomainRequest); assert.same(XDomainRequest, sinon.FakeXDomainRequest); }, "restores global XDomainRequest": function () { this.fakeXdr.restore(); assert.same(XDomainRequest, globalXDomainRequest); } } }); })(this); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/util/fake-xml-http-request-test.js000066400000000000000000002121251276775511300275320ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../../lib/sinon"); var assert = buster.assert; var refute = buster.refute; var globalXMLHttpRequest = root.XMLHttpRequest; var globalActiveXObject = root.ActiveXObject; var supportsProgressEvents = typeof ProgressEvent !== "undefined"; var supportsFormData = typeof FormData !== "undefined"; var supportsArrayBuffer = typeof ArrayBuffer !== "undefined"; var supportsBlob = (function () { try { return !!new Blob(); } catch (e) { return false; } })(); var fakeXhrSetUp = function () { this.fakeXhr = sinon.useFakeXMLHttpRequest(); }; var fakeXhrTearDown = function () { if (typeof this.fakeXhr.restore === "function") { this.fakeXhr.restore(); } }; var runWithWorkingXHROveride = function (workingXHR, test) { try { var original = sinon.xhr.workingXHR; sinon.xhr.workingXHR = workingXHR; test(); } finally { sinon.xhr.workingXHR = original; } }; var assertArrayBufferMatches = function (actual, expected) { assert(actual instanceof ArrayBuffer, "${0} expected to be an ArrayBuffer"); var actualString = ""; var actualView = new Uint8Array(actual); for (var i = 0; i < actualView.length; i++) { actualString += String.fromCharCode(actualView[i]); } assert.same(actualString, expected, "ArrayBuffer [${0}] expected to match ArrayBuffer [${1}]"); }; var assertBlobMatches = function (actual, expected, done) { var actualReader = new FileReader(); actualReader.onloadend = done(function () { assert.same(actualReader.result, expected); }); actualReader.readAsBinaryString(actual); }; var assertProgressEvent = function (event, progress) { assert.equals(event.loaded, progress); assert.equals(event.total, progress); assert.equals(event.lengthComputable, !!progress); }; var assertEventOrdering = function (event, progress, callback) { return function (done) { var expectedOrder = [ "upload:progress", "upload:" + event, "upload:loadend", "xhr:progress", "xhr:on" + event, "xhr:" + event ]; var eventOrder = []; function observe(name) { return function (e) { assertProgressEvent(e, progress); eventOrder.push(name); }; } this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.upload.addEventListener("progress", observe("upload:progress")); this.xhr.upload.addEventListener("loadend", observe("upload:loadend")); this.xhr.addEventListener("progress", observe("xhr:progress")); this.xhr.addEventListener("loadend", function (e) { assertProgressEvent(e, progress); // finish next tick to allow any events that might fire // after loadend to trigger setTimeout(function () { assert.equals(eventOrder, expectedOrder); done(); }, 1); }); // listen for abort, error, and load events to make sure only // the expected events fire ["abort", "error", "load"].forEach( function (name) { this.xhr.upload.addEventListener(name, observe("upload:" + name)); this.xhr.addEventListener(name, observe("xhr:" + name)); this.xhr["on" + name] = observe("xhr:on" + name); }, this ); callback(this.xhr); }; }; buster.testCase("sinon.FakeXMLHttpRequest", { requiresSupportFor: { "browser": typeof window !== "undefined" }, tearDown: function () { delete sinon.FakeXMLHttpRequest.onCreate; }, "is constructor": function () { assert.isFunction(sinon.FakeXMLHttpRequest); assert.same(sinon.FakeXMLHttpRequest.prototype.constructor, sinon.FakeXMLHttpRequest); }, "implements readyState constants": function () { assert.same(sinon.FakeXMLHttpRequest.OPENED, 1); assert.same(sinon.FakeXMLHttpRequest.HEADERS_RECEIVED, 2); assert.same(sinon.FakeXMLHttpRequest.LOADING, 3); assert.same(sinon.FakeXMLHttpRequest.DONE, 4); }, "calls onCreate if listener is set": function () { var onCreate = sinon.spy(); sinon.FakeXMLHttpRequest.onCreate = onCreate; // instantiating FakeXMLHttpRequest for it's onCreate side effect var xhr = new sinon.FakeXMLHttpRequest(); // eslint-disable-line no-unused-vars assert(onCreate.called); }, "passes new object to onCreate if set": function () { var onCreate = sinon.spy(); sinon.FakeXMLHttpRequest.onCreate = onCreate; var xhr = new sinon.FakeXMLHttpRequest(); assert.same(onCreate.getCall(0).args[0], xhr); }, ".withCredentials": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); }, "property is set if we support standards CORS": function () { assert.equals(sinon.xhr.supportsCORS, "withCredentials" in this.xhr); } }, ".open": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); }, "is method": function () { assert.isFunction(this.xhr.open); }, "sets properties on object": function () { this.xhr.open("GET", "/my/url", true, "cjno", "pass"); assert.equals(this.xhr.method, "GET"); assert.equals(this.xhr.url, "/my/url"); assert.isTrue(this.xhr.async); assert.equals(this.xhr.username, "cjno"); assert.equals(this.xhr.password, "pass"); }, "is async by default": function () { this.xhr.open("GET", "/my/url"); assert.isTrue(this.xhr.async); }, "sets async to false": function () { this.xhr.open("GET", "/my/url", false); assert.isFalse(this.xhr.async); }, "sets response to empty string": function () { this.xhr.open("GET", "/my/url"); assert.same(this.xhr.response, ""); }, "sets responseText to empty string": function () { this.xhr.open("GET", "/my/url"); assert.same(this.xhr.responseText, ""); }, "sets responseXML to null": function () { this.xhr.open("GET", "/my/url"); assert.isNull(this.xhr.responseXML); }, "sets requestHeaders to blank object": function () { this.xhr.open("GET", "/my/url"); assert.isObject(this.xhr.requestHeaders); assert.equals(this.xhr.requestHeaders, {}); }, "sets readyState to OPENED": function () { this.xhr.open("GET", "/my/url"); assert.same(this.xhr.readyState, sinon.FakeXMLHttpRequest.OPENED); }, "sets send flag to false": function () { this.xhr.open("GET", "/my/url"); assert.isFalse(this.xhr.sendFlag); }, "dispatches onreadystatechange with reset state": function () { var state = {}; this.xhr.onreadystatechange = function () { sinon.extend(state, this); }; this.xhr.open("GET", "/my/url"); assert.equals(state.method, "GET"); assert.equals(state.url, "/my/url"); assert.isTrue(state.async); refute.defined(state.username); refute.defined(state.password); assert.same(state.response, ""); assert.same(state.responseText, ""); assert.isNull(state.responseXML); refute.defined(state.responseHeaders); assert.equals(state.readyState, sinon.FakeXMLHttpRequest.OPENED); assert.isFalse(state.sendFlag); } }, ".setRequestHeader": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); this.xhr.open("GET", "/"); }, "throws exception if readyState is not OPENED": function () { var xhr = new sinon.FakeXMLHttpRequest(); assert.exception(function () { xhr.setRequestHeader("X-EY", "No-no"); }); }, "throws exception if send flag is true": function () { var xhr = this.xhr; xhr.sendFlag = true; assert.exception(function () { xhr.setRequestHeader("X-EY", "No-no"); }); }, "disallows unsafe headers": function () { var xhr = this.xhr; assert.exception(function () { xhr.setRequestHeader("Accept-Charset", ""); }); assert.exception(function () { xhr.setRequestHeader("Accept-Encoding", ""); }); assert.exception(function () { xhr.setRequestHeader("Connection", ""); }); assert.exception(function () { xhr.setRequestHeader("Content-Length", ""); }); assert.exception(function () { xhr.setRequestHeader("Cookie", ""); }); assert.exception(function () { xhr.setRequestHeader("Cookie2", ""); }); assert.exception(function () { xhr.setRequestHeader("Content-Transfer-Encoding", ""); }); assert.exception(function () { xhr.setRequestHeader("Date", ""); }); assert.exception(function () { xhr.setRequestHeader("Expect", ""); }); assert.exception(function () { xhr.setRequestHeader("Host", ""); }); assert.exception(function () { xhr.setRequestHeader("Keep-Alive", ""); }); assert.exception(function () { xhr.setRequestHeader("Referer", ""); }); assert.exception(function () { xhr.setRequestHeader("TE", ""); }); assert.exception(function () { xhr.setRequestHeader("Trailer", ""); }); assert.exception(function () { xhr.setRequestHeader("Transfer-Encoding", ""); }); assert.exception(function () { xhr.setRequestHeader("Upgrade", ""); }); assert.exception(function () { xhr.setRequestHeader("User-Agent", ""); }); assert.exception(function () { xhr.setRequestHeader("Via", ""); }); assert.exception(function () { xhr.setRequestHeader("Proxy-Oops", ""); }); assert.exception(function () { xhr.setRequestHeader("Sec-Oops", ""); }); }, "sets header and value": function () { this.xhr.setRequestHeader("X-Fake", "Yeah!"); assert.equals(this.xhr.requestHeaders, { "X-Fake": "Yeah!" }); }, "appends same-named header values": function () { this.xhr.setRequestHeader("X-Fake", "Oh"); this.xhr.setRequestHeader("X-Fake", "yeah!"); assert.equals(this.xhr.requestHeaders, { "X-Fake": "Oh,yeah!" }); } }, ".send": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); }, "throws if request is not open": function () { var xhr = new sinon.FakeXMLHttpRequest(); assert.exception(function () { xhr.send(); }); }, "throws if send flag is true": function () { var xhr = this.xhr; xhr.open("GET", "/"); xhr.sendFlag = true; assert.exception(function () { xhr.send(); }); }, "sets GET body to null": function () { this.xhr.open("GET", "/"); this.xhr.send("Data"); assert.isNull(this.xhr.requestBody); }, "sets HEAD body to null": function () { this.xhr.open("HEAD", "/"); this.xhr.send("Data"); assert.isNull(this.xhr.requestBody); }, "sets mime to text/plain": { requiresSupportFor: { "FormData": supportsFormData }, test: function () { this.xhr.open("POST", "/"); this.xhr.send("Data"); assert.equals(this.xhr.requestHeaders["Content-Type"], "text/plain;charset=utf-8"); } }, "does not override mime": function () { this.xhr.open("POST", "/"); this.xhr.setRequestHeader("Content-Type", "text/html"); this.xhr.send("Data"); assert.equals(this.xhr.requestHeaders["Content-Type"], "text/html;charset=utf-8"); }, "does not add new 'Content-Type' header if 'content-type' already exists": function () { this.xhr.open("POST", "/"); this.xhr.setRequestHeader("content-type", "application/json"); this.xhr.send("Data"); assert.equals(this.xhr.requestHeaders["Content-Type"], undefined); assert.equals(this.xhr.requestHeaders["content-type"], "application/json;charset=utf-8"); }, "does not add 'Content-Type' header if data is FormData": { requiresSupportFor: { "FormData": supportsFormData }, test: function () { this.xhr.open("POST", "/"); var formData = new FormData(); formData.append("username", "biz"); this.xhr.send("Data"); assert.equals(this.xhr.requestHeaders["content-type"], undefined); } }, "sets request body to string data for POST": function () { this.xhr.open("POST", "/"); this.xhr.send("Data"); assert.equals(this.xhr.requestBody, "Data"); }, "sets error flag to false": function () { this.xhr.open("POST", "/"); this.xhr.send("Data"); assert.isFalse(this.xhr.errorFlag); }, "sets send flag to true": function () { this.xhr.open("POST", "/"); this.xhr.send("Data"); assert.isTrue(this.xhr.sendFlag); }, "does not set send flag to true if sync": function () { this.xhr.open("POST", "/", false); this.xhr.send("Data"); assert.isFalse(this.xhr.sendFlag); }, "dispatches onreadystatechange": function () { var event, state; this.xhr.open("POST", "/", false); this.xhr.onreadystatechange = function (e) { event = e; state = this.readyState; }; this.xhr.send("Data"); assert.equals(state, sinon.FakeXMLHttpRequest.OPENED); assert.equals(event.type, "readystatechange"); assert.defined(event.target); }, "dispatches event using DOM Event interface": function () { var listener = sinon.spy(); this.xhr.open("POST", "/", false); this.xhr.addEventListener("readystatechange", listener); this.xhr.send("Data"); assert(listener.calledOnce); assert.equals(listener.args[0][0].type, "readystatechange"); assert.defined(listener.args[0][0].target); }, "dispatches onSend callback if set": function () { this.xhr.open("POST", "/", true); var callback = sinon.spy(); this.xhr.onSend = callback; this.xhr.send("Data"); assert(callback.called); }, "dispatches onSend with request as argument": function () { this.xhr.open("POST", "/", true); var callback = sinon.spy(); this.xhr.onSend = callback; this.xhr.send("Data"); assert(callback.calledWith(this.xhr)); }, "dispatches onSend when async": function () { this.xhr.open("POST", "/", false); var callback = sinon.spy(); this.xhr.onSend = callback; this.xhr.send("Data"); assert(callback.calledWith(this.xhr)); } }, ".setResponseHeaders": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); }, "sets request headers": function () { var object = { id: 42 }; this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.setResponseHeaders(object); assert.equals(this.xhr.responseHeaders, object); }, "calls readyStateChange with HEADERS_RECEIVED": function () { var object = { id: 42 }; this.xhr.open("GET", "/"); this.xhr.send(); var spy = this.xhr.readyStateChange = sinon.spy(); this.xhr.setResponseHeaders(object); assert(spy.calledWith(sinon.FakeXMLHttpRequest.HEADERS_RECEIVED)); }, "does not call readyStateChange if sync": function () { var object = { id: 42 }; this.xhr.open("GET", "/", false); this.xhr.send(); var spy = this.xhr.readyStateChange = sinon.spy(); this.xhr.setResponseHeaders(object); assert.isFalse(spy.called); }, "changes readyState to HEADERS_RECEIVED if sync": function () { var object = { id: 42 }; this.xhr.open("GET", "/", false); this.xhr.send(); this.xhr.setResponseHeaders(object); assert.equals(this.xhr.readyState, sinon.FakeXMLHttpRequest.HEADERS_RECEIVED); }, "throws if headers were already set": function () { var xhr = this.xhr; xhr.open("GET", "/", false); xhr.send(); xhr.setResponseHeaders({}); assert.exception(function () { xhr.setResponseHeaders({}); }); } }, ".setResponseBodyAsync": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.setResponseHeaders({}); }, "invokes onreadystatechange handler with LOADING state": function () { var spy = sinon.spy(); this.xhr.readyStateChange = spy; this.xhr.setResponseBody("Some text goes in here ok?"); assert(spy.calledWith(sinon.FakeXMLHttpRequest.LOADING)); }, "invokes onreadystatechange handler for each 10 byte chunk": function () { var spy = sinon.spy(); this.xhr.readyStateChange = spy; this.xhr.chunkSize = 10; this.xhr.setResponseBody("Some text goes in here ok?"); assert.equals(spy.callCount, 4); }, "invokes onreadystatechange handler for each x byte chunk": function () { var spy = sinon.spy(); this.xhr.readyStateChange = spy; this.xhr.chunkSize = 20; this.xhr.setResponseBody("Some text goes in here ok?"); assert.equals(spy.callCount, 3); }, "invokes onreadystatechange handler with partial data": function () { var pieces = []; var mismatch = false; this.xhr.readyStateChange = function () { if (this.response !== this.responseText) { mismatch = true; } pieces.push(this.responseText); }; this.xhr.chunkSize = 9; this.xhr.setResponseBody("Some text goes in here ok?"); assert.isFalse(mismatch); assert.equals(pieces[1], "Some text"); }, "calls onreadystatechange with DONE state": function () { var spy = sinon.spy(); this.xhr.readyStateChange = spy; this.xhr.setResponseBody("Some text goes in here ok?"); assert(spy.calledWith(sinon.FakeXMLHttpRequest.DONE)); }, "throws if not open": function () { var xhr = new sinon.FakeXMLHttpRequest(); assert.exception(function () { xhr.setResponseBody(""); }); }, "throws if no headers received": function () { var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/"); xhr.send(); assert.exception(function () { xhr.setResponseBody(""); }); }, "throws if body was already sent": function () { var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/"); xhr.send(); xhr.setResponseHeaders({}); xhr.setResponseBody(""); assert.exception(function () { xhr.setResponseBody(""); }); }, "throws if body is not a string": function () { var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/"); xhr.send(); xhr.setResponseHeaders({}); assert.exception(function () { xhr.setResponseBody({}); }, "InvalidBodyException"); }, "with ArrayBuffer support": { requiresSupportFor: { "ArrayBuffer": supportsArrayBuffer }, "invokes onreadystatechange for each chunk when responseType='arraybuffer'": function () { var spy = sinon.spy(); this.xhr.readyStateChange = spy; this.xhr.chunkSize = 10; this.xhr.responseType = "arraybuffer"; this.xhr.setResponseBody("Some text goes in here ok?"); assert.equals(spy.callCount, 4); } }, "with Blob support": { requiresSupportFor: { "Blob": supportsBlob }, "invokes onreadystatechange handler for each 10 byte chunk when responseType='blob'": function () { var spy = sinon.spy(); this.xhr.readyStateChange = spy; this.xhr.chunkSize = 10; this.xhr.responseType = "blob"; this.xhr.setResponseBody("Some text goes in here ok?"); assert.equals(spy.callCount, 4); } } }, ".setResponseBodySync": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); this.xhr.open("GET", "/", false); this.xhr.send(); this.xhr.setResponseHeaders({}); }, "does not throw": function () { var xhr = this.xhr; refute.exception(function () { xhr.setResponseBody(""); }); }, "sets readyState to DONE": function () { this.xhr.setResponseBody(""); assert.equals(this.xhr.readyState, sinon.FakeXMLHttpRequest.DONE); }, "throws if responding to request twice": function () { var xhr = this.xhr; this.xhr.setResponseBody(""); assert.exception(function () { xhr.setResponseBody(""); }); }, "calls onreadystatechange for sync request with DONE state": function () { var spy = sinon.spy(); this.xhr.readyStateChange = spy; this.xhr.setResponseBody("Some text goes in here ok?"); assert(spy.calledWith(sinon.FakeXMLHttpRequest.DONE)); }, "simulates synchronous request": function () { var xhr = new sinon.FakeXMLHttpRequest(); xhr.onSend = function () { this.setResponseHeaders({}); this.setResponseBody("Oh yeah"); }; xhr.open("GET", "/", false); xhr.send(); assert.equals(xhr.responseText, "Oh yeah"); } }, ".respond": { setUp: function () { this.sandbox = sinon.sandbox.create(); this.xhr = new sinon.FakeXMLHttpRequest(); this.xhr.open("GET", "/"); var spy = this.spy = sinon.spy(); this.xhr.onreadystatechange = function () { if (this.readyState === 4) { spy.call(this); } }; this.xhr.send(); }, tearDown: function () { this.sandbox.restore(); }, "fire onload event": function () { this.onload = this.spy; this.xhr.respond(200, {}, ""); assert.equals(this.spy.callCount, 1); }, "fire onload event with this set to the XHR object": function (done) { var xhr = new sinon.FakeXMLHttpRequest(); xhr.open("GET", "/"); xhr.onload = function () { assert.same(this, xhr); done(); }; xhr.send(); xhr.respond(200, {}, ""); }, "calls readystate handler with readyState DONE once": function () { this.xhr.respond(200, {}, ""); assert.equals(this.spy.callCount, 1); }, "defaults to status 200, no headers, and blank body": function () { this.xhr.respond(); assert.equals(this.xhr.status, 200); assert.equals(this.xhr.getAllResponseHeaders(), ""); assert.equals(this.xhr.responseText, ""); }, "sets status": function () { this.xhr.respond(201); assert.equals(this.xhr.status, 201); }, "sets status text": function () { this.xhr.respond(201); assert.equals(this.xhr.statusText, "Created"); }, "sets headers": function () { sinon.spy(this.xhr, "setResponseHeaders"); var responseHeaders = { some: "header", value: "over here" }; this.xhr.respond(200, responseHeaders); assert.equals(this.xhr.setResponseHeaders.args[0][0], responseHeaders); }, "sets response text": function () { this.xhr.respond(200, {}, "'tis some body text"); assert.equals(this.xhr.responseText, "'tis some body text"); }, "completes request when onreadystatechange fails": function () { this.sandbox.stub(sinon, "logError"); // reduce console spam in the test runner this.xhr.onreadystatechange = sinon.stub().throws(); this.xhr.respond(200, {}, "'tis some body text"); assert.equals(this.xhr.onreadystatechange.callCount, 4); }, "sets status before transitioning to readyState HEADERS_RECEIVED": function () { var status, statusText; this.xhr.onreadystatechange = function () { if (this.readyState === 2) { status = this.status; statusText = this.statusText; } }; this.xhr.respond(204); assert.equals(status, 204); assert.equals(statusText, "No Content"); } }, ".getResponseHeader": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); }, "returns null if request is not finished": function () { this.xhr.open("GET", "/"); assert.isNull(this.xhr.getResponseHeader("Content-Type")); }, "returns null if header is Set-Cookie": function () { this.xhr.open("GET", "/"); this.xhr.send(); assert.isNull(this.xhr.getResponseHeader("Set-Cookie")); }, "returns null if header is Set-Cookie2": function () { this.xhr.open("GET", "/"); this.xhr.send(); assert.isNull(this.xhr.getResponseHeader("Set-Cookie2")); }, "returns header value": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.setResponseHeaders({ "Content-Type": "text/html" }); assert.equals(this.xhr.getResponseHeader("Content-Type"), "text/html"); }, "returns header value if sync": function () { this.xhr.open("GET", "/", false); this.xhr.send(); this.xhr.setResponseHeaders({ "Content-Type": "text/html" }); assert.equals(this.xhr.getResponseHeader("Content-Type"), "text/html"); }, "returns null if header is not set": function () { this.xhr.open("GET", "/"); this.xhr.send(); assert.isNull(this.xhr.getResponseHeader("Content-Type")); }, "returns headers case insensitive": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.setResponseHeaders({ "Content-Type": "text/html" }); assert.equals(this.xhr.getResponseHeader("content-type"), "text/html"); } }, ".getAllResponseHeaders": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); }, "returns empty string if request is not finished": function () { this.xhr.open("GET", "/"); assert.equals(this.xhr.getAllResponseHeaders(), ""); }, "does not return Set-Cookie and Set-Cookie2 headers": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.setResponseHeaders({ "Set-Cookie": "Hey", "Set-Cookie2": "There" }); assert.equals(this.xhr.getAllResponseHeaders(), ""); }, "returns headers": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.setResponseHeaders({ "Content-Type": "text/html", "Set-Cookie2": "There", "Content-Length": "32" }); assert.equals(this.xhr.getAllResponseHeaders(), "Content-Type: text/html\r\nContent-Length: 32\r\n"); }, "returns headers if sync": function () { this.xhr.open("GET", "/", false); this.xhr.send(); this.xhr.setResponseHeaders({ "Content-Type": "text/html", "Set-Cookie2": "There", "Content-Length": "32" }); assert.equals(this.xhr.getAllResponseHeaders(), "Content-Type: text/html\r\nContent-Length: 32\r\n"); } }, ".abort": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); }, "sets aborted flag to true": function () { this.xhr.aborted = true; this.xhr.abort(); assert.isTrue(this.xhr.aborted); }, "sets response to empty string": function () { this.xhr.response = "Partial data"; this.xhr.abort(); assert.same(this.xhr.response, ""); }, "sets responseText to empty string": function () { this.xhr.responseText = "Partial data"; this.xhr.abort(); assert.same(this.xhr.responseText, ""); }, "sets errorFlag to true": function () { this.xhr.abort(); assert.isTrue(this.xhr.errorFlag); }, "nulls request headers": function () { this.xhr.open("GET", "/"); this.xhr.setRequestHeader("X-Test", "Sumptn"); this.xhr.abort(); assert.equals(this.xhr.requestHeaders, {}); }, "does not have undefined response headers": function () { this.xhr.open("GET", "/"); this.xhr.abort(); assert.defined(this.xhr.responseHeaders); }, "nulls response headers": function () { this.xhr.open("GET", "/"); this.xhr.abort(); assert.equals(this.xhr.responseHeaders, {}); }, "sets state to DONE if sent before": function () { var readyState; this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.onreadystatechange = function () { readyState = this.readyState; }; this.xhr.abort(); assert.equals(readyState, sinon.FakeXMLHttpRequest.DONE); }, "sets send flag to false if sent before": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.abort(); assert.isFalse(this.xhr.sendFlag); }, "dispatches readystatechange event if sent before": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.onreadystatechange = sinon.stub(); this.xhr.abort(); assert(this.xhr.onreadystatechange.called); }, "sets readyState to unsent if sent before": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.abort(); assert.equals(this.xhr.readyState, sinon.FakeXMLHttpRequest.UNSENT); }, "does not dispatch readystatechange event if readyState is unsent": function () { this.xhr.onreadystatechange = sinon.stub(); this.xhr.abort(); assert.isFalse(this.xhr.onreadystatechange.called); }, "does not dispatch readystatechange event if readyState is opened but not sent": function () { this.xhr.open("GET", "/"); this.xhr.onreadystatechange = sinon.stub(); this.xhr.abort(); assert.isFalse(this.xhr.onreadystatechange.called); }, "follows request abort event steps": assertEventOrdering("abort", 0, function (xhr) { xhr.abort(); }) }, ".error": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); }, "sets response to empty string": function () { this.xhr.response = "Partial data"; this.xhr.error(); assert.same(this.xhr.response, ""); }, "sets responseText to empty string": function () { this.xhr.responseText = "Partial data"; this.xhr.error(); assert.same(this.xhr.responseText, ""); }, "sets errorFlag to true": function () { this.xhr.errorFlag = false; this.xhr.error(); assert.isTrue(this.xhr.errorFlag); }, "nulls request headers": function () { this.xhr.open("GET", "/"); this.xhr.setRequestHeader("X-Test", "Sumptn"); this.xhr.error(); assert.equals(this.xhr.requestHeaders, {}); }, "nulls response headers": function () { this.xhr.open("GET", "/"); this.xhr.error(); assert.equals(this.xhr.responseHeaders, {}); }, "dispatches readystatechange event if sent before": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.onreadystatechange = sinon.stub(); this.xhr.error(); assert(this.xhr.onreadystatechange.called); }, "sets readyState to DONE": function () { this.xhr.open("GET", "/"); this.xhr.error(); assert.equals(this.xhr.readyState, sinon.FakeXMLHttpRequest.DONE); }, "follows request error event steps": assertEventOrdering("error", 0, function (xhr) { xhr.error(); }) }, ".response": { requiresSupportFor: { "browser": typeof window !== "undefined" }, setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); }, "is initially the empty string if responseType === ''": function () { this.xhr.responseType = ""; this.xhr.open("GET", "/"); assert.same(this.xhr.response, ""); }, "is initially the empty string if responseType === 'text'": function () { this.xhr.responseType = "text"; this.xhr.open("GET", "/"); assert.same(this.xhr.response, ""); }, "is initially null if responseType === 'json'": function () { this.xhr.responseType = "json"; this.xhr.open("GET", "/"); assert.isNull(this.xhr.response); }, "is initially null if responseType === 'document'": function () { this.xhr.responseType = "document"; this.xhr.open("GET", "/"); assert.isNull(this.xhr.response); }, "is the empty string when the response body is empty": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, {}, ""); assert.same(this.xhr.response, ""); }, "parses JSON for responseType='json'": function () { this.xhr.responseType = "json"; this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, { "Content-Type": "application/json" }, JSON.stringify({foo: true})); var response = this.xhr.response; assert.isObject(response); assert.isTrue(response.foo); }, "does not parse JSON if responseType!='json'": function () { this.xhr.open("GET", "/"); this.xhr.send(); var responseText = JSON.stringify({foo: true}); this.xhr.respond(200, { "Content-Type": "application/json" }, responseText); var response = this.xhr.response; assert.isString(response); assert.equals(response, responseText); }, "with ArrayBuffer support": { requiresSupportFor: { "ArrayBuffer": supportsArrayBuffer }, "is initially null if responseType === 'arraybuffer'": function () { this.xhr.responseType = "arraybuffer"; this.xhr.open("GET", "/"); assert.isNull(this.xhr.response); }, "defaults to empty ArrayBuffer response": function () { this.xhr.responseType = "arraybuffer"; this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(); assertArrayBufferMatches(this.xhr.response, ""); }, "returns ArrayBuffer when responseType='arraybuffer'": function () { this.xhr.responseType = "arraybuffer"; this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, { "Content-Type": "application/octet-stream" }, "a test buffer"); assertArrayBufferMatches(this.xhr.response, "a test buffer"); }, "returns binary data correctly when responseType='arraybuffer'": function () { this.xhr.responseType = "arraybuffer"; this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, { "Content-Type": "application/octet-stream" }, "\xFF"); assertArrayBufferMatches(this.xhr.response, "\xFF"); } }, "with Blob support": { requiresSupportFor: { "Blob": supportsBlob }, "is initially null if responseType === 'blob'": function () { this.xhr.responseType = "blob"; this.xhr.open("GET", "/"); assert.isNull(this.xhr.response); }, "defaults to empty Blob response": function (done) { this.xhr.responseType = "blob"; this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(); assertBlobMatches(this.xhr.response, "", done); }, "returns blob with correct data": function (done) { this.xhr.responseType = "blob"; this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, { "Content-Type": "application/octet-stream" }, "a test blob"); assertBlobMatches(this.xhr.response, "a test blob", done); }, "returns blob with correct binary data": function (done) { this.xhr.responseType = "blob"; this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, { "Content-Type": "application/octet-stream" }, "\xFF"); assertBlobMatches(this.xhr.response, "\xFF", done); } } }, ".responseXML": { requiresSupportFor: { "browser": typeof window !== "undefined" }, setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); }, "is initially null": function () { this.xhr.open("GET", "/"); assert.isNull(this.xhr.responseXML); }, "is null when the response body is empty": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, {}, ""); assert.isNull(this.xhr.responseXML); }, "parses XML for application/xml": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, { "Content-Type": "application/xml" }, "

Hola!

"); var doc = this.xhr.responseXML; var elements = doc.documentElement.getElementsByTagName("h1"); assert.equals(elements.length, 1); assert.equals(elements[0].tagName, "h1"); }, "parses XML for text/xml": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, { "Content-Type": "text/xml" }, "

Hola!

"); refute.isNull(this.xhr.responseXML); }, "parses XML for custom xml content type": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, { "Content-Type": "application/text+xml" }, "

Hola!

"); refute.isNull(this.xhr.responseXML); }, "parses XML with no Content-Type": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, {}, "

Hola!

"); var doc = this.xhr.responseXML; var elements = doc.documentElement.getElementsByTagName("h1"); assert.equals(elements.length, 1); assert.equals(elements[0].tagName, "h1"); }, "does not parse XML with Content-Type text/plain": function () { this.xhr.open("GET", "/"); this.xhr.send(); this.xhr.respond(200, { "Content-Type": "text/plain" }, "
"); assert.isNull(this.xhr.responseXML); }, "does not parse XML with Content-Type text/plain if sync": function () { this.xhr.open("GET", "/", false); this.xhr.send(); this.xhr.respond(200, { "Content-Type": "text/plain" }, "
"); assert.isNull(this.xhr.responseXML); } }, "stub XHR": { setUp: fakeXhrSetUp, tearDown: fakeXhrTearDown, "returns FakeXMLHttpRequest constructor": function () { assert.same(this.fakeXhr, sinon.FakeXMLHttpRequest); }, "temporarily blesses FakeXMLHttpRequest with restore method": function () { assert.isFunction(this.fakeXhr.restore); }, "calling restore removes temporary method": function () { this.fakeXhr.restore(); refute.defined(this.fakeXhr.restore); }, "removes XMLHttpRequest onCreate listener": function () { sinon.FakeXMLHttpRequest.onCreate = function () {}; this.fakeXhr.restore(); refute.defined(sinon.FakeXMLHttpRequest.onCreate); }, "optionally keeps XMLHttpRequest onCreate listener": function () { var onCreate = function () {}; sinon.FakeXMLHttpRequest.onCreate = onCreate; this.fakeXhr.restore(true); assert.same(sinon.FakeXMLHttpRequest.onCreate, onCreate); } }, ".filtering": { setUp: function () { sinon.FakeXMLHttpRequest.useFilters = true; sinon.FakeXMLHttpRequest.filters = []; sinon.useFakeXMLHttpRequest(); }, tearDown: function () { sinon.FakeXMLHttpRequest.useFilters = false; sinon.FakeXMLHttpRequest.restore(); if (sinon.FakeXMLHttpRequest.defake.restore) { sinon.FakeXMLHttpRequest.defake.restore(); } }, "does not defake XHR requests that don't match a filter": { requiresSupportFor: { "XMLHttpRequest": typeof XMLHttpRequest !== "undefined" }, test: function () { sinon.stub(sinon.FakeXMLHttpRequest, "defake"); sinon.FakeXMLHttpRequest.addFilter(function () { return false; }); new XMLHttpRequest().open("GET", "http://example.com"); refute(sinon.FakeXMLHttpRequest.defake.called); } }, "defakes XHR requests that match a filter": { requiresSupportFor: { "XMLHttpRequest": typeof XMLHttpRequest !== "undefined" }, test: function () { sinon.stub(sinon.FakeXMLHttpRequest, "defake"); sinon.FakeXMLHttpRequest.addFilter(function () { return true; }); new XMLHttpRequest().open("GET", "http://example.com"); assert(sinon.FakeXMLHttpRequest.defake.calledOnce); } } }, "defaked XHR": { setUp: function () { this.fakeXhr = new sinon.FakeXMLHttpRequest(); }, "updates attributes from working XHR object when ready state changes": function () { var workingXHRInstance, readyStateCb; var workingXHROverride = function () { workingXHRInstance = this; this.addEventListener = function (str, fn) { readyStateCb = fn; }; this.open = function () {}; }; var fakeXhr = this.fakeXhr; runWithWorkingXHROveride(workingXHROverride, function () { sinon.FakeXMLHttpRequest.defake(fakeXhr, []); workingXHRInstance.statusText = "This is the status text of the real XHR"; workingXHRInstance.readyState = 4; readyStateCb(); assert.equals(fakeXhr.statusText, "This is the status text of the real XHR"); }); }, "passes on methods to working XHR object": function () { var workingXHRInstance, spy; var workingXHROverride = function () { workingXHRInstance = this; this.addEventListener = this.open = function () {}; }; var fakeXhr = this.fakeXhr; runWithWorkingXHROveride(workingXHROverride, function () { sinon.FakeXMLHttpRequest.defake(fakeXhr, []); workingXHRInstance.getResponseHeader = spy = sinon.spy(); fakeXhr.getResponseHeader(); assert(spy.calledOnce); }); }, "calls legacy onreadystatechange handlers with target set to fakeXHR": function () { var spy, readyStateCb; var workingXHROverride = function () { this.addEventListener = function (str, fn) { readyStateCb = fn; }; this.open = function () {}; }; var fakeXhr = this.fakeXhr; runWithWorkingXHROveride(workingXHROverride, function () { sinon.FakeXMLHttpRequest.defake(fakeXhr, []); fakeXhr.onreadystatechange = spy = sinon.spy(); readyStateCb(); assert(spy.calledOnce); // Fix to make weinre work assert.isObject(spy.args[0][0]); assert.equals(spy.args[0][0].target, fakeXhr); }); }, "performs initial readystatechange on opening when filters are being used, but don't match": function () { try { sinon.FakeXMLHttpRequest.useFilters = true; var spy = sinon.spy(); this.fakeXhr.addEventListener("readystatechange", spy); this.fakeXhr.open("GET", "http://example.com", true); assert(spy.calledOnce); } finally { sinon.FakeXMLHttpRequest.useFilters = false; } } }, "defaked XHR filters": { setUp: function () { sinon.FakeXMLHttpRequest.useFilters = true; sinon.FakeXMLHttpRequest.filters = []; sinon.useFakeXMLHttpRequest(); sinon.FakeXMLHttpRequest.addFilter(function () { return true; }); }, tearDown: function () { sinon.FakeXMLHttpRequest.useFilters = false; sinon.FakeXMLHttpRequest.filters = []; sinon.FakeXMLHttpRequest.restore(); }, "// loads resource asynchronously": function (done) { var req = new XMLHttpRequest(); req.onreadystatechange = function () { if (this.readyState === 4) { assert.match(this.responseText, /loaded successfully/); assert.match(this.response, /loaded successfully/); done(); } }; req.open("GET", "/test/resources/xhr_target.txt", true); req.send(); }, "// loads resource synchronously": function () { var req = new XMLHttpRequest(); req.open("GET", "/test/resources/xhr_target.txt", false); req.send(); assert.match(req.responseText, /loaded successfully/); assert.match(req.response, /loaded successfully/); } }, "missing ActiveXObject": { requiresSupportFor: { "no ActiveXObject": typeof ActiveXObject === "undefined" }, setUp: fakeXhrSetUp, tearDown: fakeXhrTearDown, "does not expose ActiveXObject": function () { assert.equals(typeof ActiveXObject, "undefined"); }, "does not expose ActiveXObject when restored": function () { this.fakeXhr.restore(); assert.equals(typeof ActiveXObject, "undefined"); } }, "native ActiveXObject": { requiresSupportFor: { ActiveXObject: typeof ActiveXObject !== "undefined" }, setUp: fakeXhrSetUp, tearDown: fakeXhrTearDown, "hijacks ActiveXObject": function () { refute.same(root.ActiveXObject, globalActiveXObject); refute.same(window.ActiveXObject, globalActiveXObject); refute.same(ActiveXObject, globalActiveXObject); // eslint-disable-line no-undef }, "restores global ActiveXObject": function () { this.fakeXhr.restore(); assert.same(root.ActiveXObject, globalActiveXObject); assert.same(window.ActiveXObject, globalActiveXObject); assert.same(ActiveXObject, globalActiveXObject); // eslint-disable-line no-undef }, "creates FakeXHR object with ActiveX Microsoft.XMLHTTP": function () { var xhr = new ActiveXObject("Microsoft.XMLHTTP"); // eslint-disable-line no-undef assert(xhr instanceof sinon.FakeXMLHttpRequest); }, "creates FakeXHR object with ActiveX Msxml2.XMLHTTP": function () { var xhr = new ActiveXObject("Msxml2.XMLHTTP"); // eslint-disable-line no-undef assert(xhr instanceof sinon.FakeXMLHttpRequest); }, "creates FakeXHR object with ActiveX Msxml2.XMLHTTP.3.0": function () { var xhr = new ActiveXObject("Msxml2.XMLHTTP.3.0"); // eslint-disable-line no-undef assert(xhr instanceof sinon.FakeXMLHttpRequest); }, "creates FakeXHR object with ActiveX Msxml2.XMLHTTP.6.0": function () { var xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0"); // eslint-disable-line no-undef assert(xhr instanceof sinon.FakeXMLHttpRequest); } }, "missing native XHR": { requiresSupportFor: { "no native XHR": typeof XMLHttpRequest === "undefined" }, setUp: fakeXhrSetUp, tearDown: fakeXhrTearDown, "does not expose XMLHttpRequest": function () { assert.equals(typeof XMLHttpRequest, "undefined"); }, "does not expose XMLHttpRequest after restore": function () { this.fakeXhr.restore(); assert.equals(typeof XMLHttpRequest, "undefined"); } }, "native XHR": { requiresSupportFor: { XHR: typeof XMLHttpRequest !== "undefined" }, setUp: fakeXhrSetUp, tearDown: fakeXhrTearDown, "replaces global XMLHttpRequest": function () { refute.same(XMLHttpRequest, globalXMLHttpRequest); assert.same(XMLHttpRequest, sinon.FakeXMLHttpRequest); }, "restores global XMLHttpRequest": function () { this.fakeXhr.restore(); assert.same(XMLHttpRequest, globalXMLHttpRequest); } }, "progress events": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); this.xhr.open("GET", "/some/url"); }, "triggers 'loadstart' event on #send": function (done) { this.xhr.addEventListener("loadstart", function () { assert(true); done(); }); this.xhr.send(); }, "triggers 'loadstart' with event target set to the XHR object": function (done) { var xhr = this.xhr; this.xhr.addEventListener("loadstart", function (event) { assert.same(xhr, event.target); done(); }); this.xhr.send(); }, "calls #onloadstart on #send": function (done) { this.xhr.onloadstart = function () { assert(true); done(); }; this.xhr.send(); }, "triggers 'load' event on success": function (done) { var xhr = this.xhr; this.xhr.addEventListener("load", function () { assert.equals(xhr.readyState, sinon.FakeXMLHttpRequest.DONE); refute.equals(xhr.status, 0); done(); }); this.xhr.send(); this.xhr.respond(200, {}, ""); }, "triggers 'load' event on for non-200 events": assertEventOrdering("load", 50, function (xhr) { // error is 50 chars long xhr.respond(500, {}, Array(51).join("x")); }), "triggers 'load' with event target set to the XHR object": function (done) { var xhr = this.xhr; this.xhr.addEventListener("load", function (event) { assert.same(xhr, event.target); done(); }); this.xhr.send(); this.xhr.respond(200, {}, ""); }, "calls #onload on success": function (done) { var xhr = this.xhr; this.xhr.onload = function () { assert.equals(xhr.readyState, sinon.FakeXMLHttpRequest.DONE); refute.equals(xhr.status, 0); done(); }; this.xhr.send(); this.xhr.respond(200, {}, ""); }, "does not trigger 'load' event on abort": function (done) { this.xhr.addEventListener("load", function () { assert(false); }); this.xhr.addEventListener("abort", function () { assert(true); // finish on next tick setTimeout(done, 0); }); this.xhr.send(); this.xhr.abort(); }, "triggers 'abort' event on cancel": function (done) { var xhr = this.xhr; this.xhr.addEventListener("abort", function () { assert.equals(xhr.readyState, sinon.FakeXMLHttpRequest.DONE); assert.equals(xhr.status, 0); setTimeout(function () { assert.equals(xhr.readyState, sinon.FakeXMLHttpRequest.UNSENT); done(); }, 0); }); this.xhr.send(); this.xhr.abort(); }, "triggers 'abort' with event target set to the XHR object": function (done) { var xhr = this.xhr; this.xhr.addEventListener("abort", function (event) { assert.same(xhr, event.target); done(); }); this.xhr.send(); this.xhr.abort(); }, "calls #onabort on cancel": function (done) { var xhr = this.xhr; this.xhr.onabort = function () { assert.equals(xhr.readyState, sinon.FakeXMLHttpRequest.DONE); assert.equals(xhr.status, 0); done(); }; this.xhr.send(); this.xhr.abort(); }, "triggers 'loadend' event at the end": function (done) { this.xhr.addEventListener("loadend", function (e) { assertProgressEvent(e, 0); done(); }); this.xhr.send(); this.xhr.respond(403, {}, ""); }, "triggers 'loadend' with event target set to the XHR object": function (done) { var xhr = this.xhr; this.xhr.addEventListener("loadend", function (event) { assert.same(xhr, event.target); done(); }); this.xhr.send(); this.xhr.respond(200, {}, ""); }, "calls #onloadend at the end": function (done) { this.xhr.onloadend = function (e) { assertProgressEvent(e, 0); done(); }; this.xhr.send(); this.xhr.respond(403, {}, ""); }, "triggers (download) progress event when response is done": { requiresSupportFor: { "ProgressEvent": supportsProgressEvents }, test: function (done) { this.xhr.addEventListener("progress", function (e) { assert.equals(e.total, 100); assert.equals(e.loaded, 20); assert.isTrue(e.lengthComputable); done(); }); this.xhr.downloadProgress({ total: 100, loaded: 20 }); } }, "follows request load event steps": assertEventOrdering("load", 27, function (xhr) { xhr.respond(200, {}, "This line is 27 chars long."); }) }, "xhr.upload": { setUp: function () { this.xhr = new sinon.FakeXMLHttpRequest(); this.xhr.open("POST", "/some/url", true); }, "progress event is triggered with xhr.uploadProgress({loaded: 20, total: 100})": { requiresSupportFor: { "ProgressEvent": supportsProgressEvents }, test: function (done) { this.xhr.upload.addEventListener("progress", function (e) { assert.equals(e.total, 100); assert.equals(e.loaded, 20); assert.isTrue(e.lengthComputable); done(); }); this.xhr.uploadProgress({ total: 100, loaded: 20 }); } }, "triggers 'load' event on success": function (done) { var xhr = this.xhr; this.xhr.upload.addEventListener("load", function () { assert.equals(xhr.readyState, sinon.FakeXMLHttpRequest.DONE); refute.equals(xhr.status, 0); done(); }); this.xhr.send(); this.xhr.respond(200, {}, ""); }, "fires event with 100% progress on 'load'": { requiresSupportFor: { "ProgressEvent": supportsProgressEvents }, test: function (done) { this.xhr.upload.addEventListener("progress", function (e) { assert.equals(e.total, 100); assert.equals(e.loaded, 100); done(); }); this.xhr.send(); // 100 character string this.xhr.respond(200, {}, Array(101).join("x")); } }, "fires events in an order similar to a browser": function (done) { var xhr = this.xhr; var events = []; this.xhr.upload.addEventListener("progress", function (e) { events.push(e.type); }); this.xhr.upload.addEventListener("load", function (e) { events.push(e.type); }); this.xhr.addEventListener("readystatechange", function (e) { if (xhr.readyState === 4) { events.push(e.type); if (supportsProgressEvents) { assert.equals(events.splice(0, 1)[0], "progress"); } assert.equals(events, ["load", "readystatechange"]); done(); } }); this.xhr.send(); this.xhr.respond(200, {}, ""); }, "calls 'abort' on cancel": function (done) { var xhr = this.xhr; this.xhr.upload.addEventListener("abort", function () { assert.equals(xhr.readyState, sinon.FakeXMLHttpRequest.DONE); assert.equals(xhr.status, 0); setTimeout(function () { assert.equals(xhr.readyState, sinon.FakeXMLHttpRequest.UNSENT); done(); }, 0); }); this.xhr.send(); this.xhr.abort(); }, "error event": { requiresSupportFor: { CustomEvent: typeof CustomEvent !== "undefined" }, "is triggered with xhr.uploadError(new Error('foobar'))": function (done) { this.xhr.upload.addEventListener("error", function (e) { assert.equals(e.detail.message, "foobar"); done(); }); this.xhr.uploadError(new Error("foobar")); } }, "event listeners can be removed": function () { var callback = function () {}; this.xhr.upload.addEventListener("load", callback); this.xhr.upload.removeEventListener("load", callback); assert.equals(this.xhr.upload.eventListeners.load.length, 0); } } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/walk-test.js000066400000000000000000000130171276775511300233430ustar00rootroot00000000000000(function (root) { "use strict"; var buster = root.buster || require("buster"); var sinon = root.sinon || require("../lib/sinon"); var assert = buster.assert; buster.testCase("sinon.walk", { "should call iterator with value, key, and obj, with context as the receiver": function () { var target = Object.create(null); var rcvr = {}; var iterator = sinon.spy(); target.hello = "world"; target.foo = 15; sinon.walk(target, iterator, rcvr); assert(iterator.calledTwice); assert(iterator.alwaysCalledOn(rcvr)); assert(iterator.calledWithExactly("world", "hello", target)); assert(iterator.calledWithExactly(15, "foo", target)); }, "should work with non-enumerable properties": function () { var target = Object.create(null); var iterator = sinon.spy(); target.hello = "world"; Object.defineProperty(target, "foo", { value: 15 }); sinon.walk(target, iterator); assert(iterator.calledTwice); assert(iterator.calledWith("world", "hello")); assert(iterator.calledWith(15, "foo")); }, "should walk the prototype chain of an object": function () { var parentProto, proto, target, iterator; parentProto = Object.create(null, { nonEnumerableParentProp: { value: "non-enumerable parent prop" }, enumerableParentProp: { value: "enumerable parent prop", enumerable: true } }); proto = Object.create(parentProto, { nonEnumerableProp: { value: "non-enumerable prop" }, enumerableProp: { value: "enumerable prop", enumerable: true } }); target = Object.create(proto, { nonEnumerableOwnProp: { value: "non-enumerable own prop" }, enumerableOwnProp: { value: "enumerable own prop", enumerable: true } }); iterator = sinon.spy(); sinon.walk(target, iterator); assert.equals(iterator.callCount, 6); assert(iterator.calledWith("non-enumerable own prop", "nonEnumerableOwnProp", target)); assert(iterator.calledWith("enumerable own prop", "enumerableOwnProp", target)); assert(iterator.calledWith("non-enumerable prop", "nonEnumerableProp", proto)); assert(iterator.calledWith("enumerable prop", "enumerableProp", proto)); assert(iterator.calledWith("non-enumerable parent prop", "nonEnumerableParentProp", parentProto)); assert(iterator.calledWith("enumerable parent prop", "enumerableParentProp", parentProto)); }, "should always invoke getters on the original receiving object": function () { var Target = function Target() { this.o = { foo: "foo" }; }; Object.defineProperty(Target.prototype, "computedFoo", { enumerable: true, get: function () { return "computed " + this.o.foo; } }); var target = new Target(); var iterator = sinon.spy(); sinon.walk(target, iterator); assert(iterator.calledWith("computed foo", "computedFoo", target)); }, "should fall back to for..in if getOwnPropertyNames is not available": function () { var getOwnPropertyNames = Object.getOwnPropertyNames; var Target = function Target() { this.hello = "world"; }; var target = new Target(); var rcvr = {}; var iterator = sinon.spy(); var err = null; var numCalls = 0; var placeholder; // eslint-disable-line no-unused-vars Target.prototype.foo = 15; Object.getOwnPropertyNames = null; // Different environments may be inconsistent in how they handle for..in, therefore we // use it to track the number of expected calls, rather than setting it to a hard // number. /* eslint-disable guard-for-in */ for (placeholder in target) { numCalls++; } /* eslint-enable guard-for-in */ try { sinon.walk(target, iterator, rcvr); assert.equals(iterator.callCount, numCalls); assert(iterator.alwaysCalledOn(rcvr)); assert(iterator.calledWith("world", "hello")); assert(iterator.calledWith(15, "foo")); } catch(e) { err = e; } finally { Object.getOwnPropertyNames = getOwnPropertyNames; } assert.isNull(err, "sinon.walk tests failed with message '" + (err && err.message) + "'"); }, "does not walk the same property twice": function () { var parent = { func: function () {} }; var child = sinon.create(parent); child.func = function () {}; var iterator = sinon.spy(); sinon.walk(child, iterator); assert.equals(iterator.callCount, 1); } }); }(this)); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/webworker-script.js000066400000000000000000000005471276775511300247450ustar00rootroot00000000000000/* eslint-env worker */ /* global sinon */ (function () { "use strict"; // Abort if we are not running in a WebWorker if ( typeof importScripts === "undefined" ) { return; } importScripts("../pkg/sinon.js"); var stub = sinon.stub().returns("worker response"); onmessage = function () { postMessage( stub() ); }; })(); sinon-4eaad42f0715face6b53899fad7bcbc49d079417/test/webworker-support-assessment.js000066400000000000000000000015601276775511300273340ustar00rootroot00000000000000(function (root) { "use strict"; var supportsWorkers = typeof root.Worker !== "undefined"; var buster = root.buster || require("buster"); var assert = buster.assert; buster.testCase("WebWorker support", { requiresSupportFor: { WebWorker: supportsWorkers }, "should not crash": function (done) { var worker = new root.Worker("./test/webworker-script.js"); worker.onmessage = function (msg) { try { assert.same(msg.data, "worker response"); done(); }catch (err) { done(err); } }; function onError(err) { done(new Error(err.message)); } worker.addEventListener("error", onError, false); worker.postMessage("whatever"); } }); })(this);