UNPKG

fzkes

Version:
237 lines (157 loc) 6.56 kB
fzkes ===== A faking library I must immediately apologize for the name; it is a horrible pun combining `fzk` (a shortening of the name of my company) and `fakes`. But it does have a nice ring to it, and I want it to be short and unique. So there it is. How to use ---------- ### Creating fakes var fzkes = require('fzkes') // Creating a stand-alone fake, great for use as a callback var fake = fzkes.fake() // For overriding an original function, great for restoring later var fs = require('fs') fzkes.fake(fs, 'readFile') // For faking all functions on an object fzkes.fakeAll(fs) #### fakeAll The `fzkes.fakeAll()` function can take an options-dictionary, allowing for overriding the default action. The options are: - `callsOriginal`: The default. `fake.callsOriginal()` is evoked on all fakes. - `none`: No action is taken on the fakes. - `throws`: A `'Fake not overridden'` exception will be evoked on all fakes. All fakes can of course be overridden later on, the default is just what should happen out-of-the-box. ### Resetting fakes Resetting a fake (`fake.reset()`) will set its internal state to what it was when it was new. It is possible to reset all fakes by calling `fzkes.reset()` or `scope.reset()`. ### Restoring original functions There are three ways to easily doing this, depending on the scope: 1. Restoring a single fake: `fake.restore()` 2. Restoring all fakes across the board: `fzkes.restore()` The last is a bit more tricky; A sub-scope can be creating by calling `fzkes.scope()`. The scope have all methods (except `chai`) that the original `fzkes` object have, except the `restore()` function on a scope only affects fakes created within that scope. ### Injecting data fake.returns('abc') fake.throws(new Error('some error')) fake.calls(function() { console.log('was called') }) // If it replaced a function on an object: fake.callsOriginal() // Conditional injects fake.withArgs(1,2).returns(3) fake.withArgs(1,2).callsOriginal() Each action (`returns`, `throws`, `calls`, etc) returns the fake, to make it easier to assign to return values and the like: fake.returns({ a: fzkes.fake('a').returns(3), b: fzkes.fake('b').throws() }) It can also chain the withArgs() automatically: var fake = fzkes.fake('name') .returns(1) .withArgs(1,2).returns(3) .withArgs(1,3).returns(4) .withArgs(1,4).throws(new Error('some error')) fake(1,1) // => 1 fake(1,2) // => 3 fake(1,3) // => 4 fake(1,4) // => throws #### Advanced `withArgs` There is a more advanced form of `withArgs` called `withComplexArgs`. It allows for skipping arguments entirely, as well as defining regular expressions to validate against strings. var fake = fzkes.fake('name') .returns(1) .withComplexArgs(null, { value: 2 }).returns(2) .withComplexArgs({ regex: /ab?c/ }).returns(3) fake(1, 1) // => 1 fake(1, 2) // => 2 fake('a', 2) // => 2 fake('abc') // => 3 fake('ac') // => 3 ### Calling callbacks There is a built-in helper for calling callbacks: `callsArg`. If the callback throws an exception, the fake with throw it as well. It can take the following options: - `notify`: A function to notify whenever the fake is called. It is called as `function(error, returnValue)`, where `error` is whatever the callback threw, and `returnValue` is what the callback returned. If `async` is false, the fake will return whatever the `notify` function returns. This option is also perfect for [mocha][mocha] style async handlers. - `returns`: A value to return whenever the fake is called. This takes presedence over the return-value of `notify`, but exceptions still triumph. - `now`: A flag that determines if the action should occur for future calls or for the first unhandled call. This will throw if the fake have no unhandled calls. - `async`: A flag determining if the callback should be called immediately or in the next tick (which would simulate an async call). - `arg`: The argument to call. This can be the parameter index (0-n), `'first'` or `'last'`. It defaults to `'last'`. - `arguments`: An array of the arguments to pass to the callback. Examples follow: // Default is calling the last function found, node-style fake.callsArg() // It can be controlled fake.callsArg({ arg: 'first' }) // 0-indexed argument list fake.callsArg({ arg: 1 }) // It defaults to calling the callback immediately, but this can be changed fake.callsArg({ async: true }) // Default is no parameters to the callback, but these can be controlled fake.callsArg({ arguments: [ 1, 2 ] }) [mocha]: http://mochajs.org/ ### Emulating calls after they have been called Sometimes, it is not feasible to prepare the fake properly; in these cases, emulating the call after the fact makes the code much better. `fzkes` supports this as an option for the `fake.calls()`, `fake.callsArg()` and `fake.callsOriginal()` functions. The code would look as the following: fake(1,2,3) fake.calls(fn, { now: true }) fake.callsOriginal({ now: true }) fake.callsArg({ now: true }) It works with all other options on the `fake.callsArg()` call. It forwards the next unhandled call as it appeared on the `fake`, and throws an exception if there are no unhandled calls: fake(1,2,3) // Goes through fake.callsOriginal({ now: true }) try { fake.calls(fn, { now: true }) } catch(e) { // e.message would say that fake had no unhandled calls. } If any of the functions was set up in advance, calls are not considered unhandled, and any call with `{ now: true }` will throw an exception. To begin building unhandled calls, make a `fake.calls(null)` invocation. fake.callsOriginal() // this call is handled immediately fake() expect(function() { fake.callsOriginal({ now: true }) }).to.throw() // resetting the expectations fake.calls(null) // it now works again fake() fake.callsOriginal({ now: true }) ### Asserting fake.wasCalled() fake.wasCalledWith(1, 2, 3) fake.wasCalledWithExactly(1, 2, 3) fake.callCount == 2 ### Using with [chai](http://chaijs.com) chai.use(fzkes) fake.should.have.been.called // at least once fake.should.have.been.called(2) // precisely 2 times fake.should.have.been.calledWith(1,2,3) ### Running in the browser Use a tool like browserify or webpack to generate a browser-compatible version of the tests. Then simply follow the guide above for setting it up and interacting with it. __NOTE:__ Pre v0.15, the package built a browser-version always. This task have now been delegated to the consumer of the library.