UNPKG

mary

Version:

Dr. Mary - JavaScript (CoffeeScript) BDD in Object-Oriented way.

239 lines (214 loc) 6.61 kB
# [Dr. Mary](https://github.com/alexeypetrushin/mary) - # JavaScript (CoffeeScript) BDD in Object-Oriented way. # # 'Mary'.should match: /ry/ # 'Mary'.should be: 'Mary' # 'Mary'.should contain: 'ry' # 'Mary'.should beEqualTo: 'Mary' # # 10.should beGreaterThan: 9 # # fun = -> throw 'some bug' # (-> fun()).should throw: 'some bug' # # _(null).should be: null # # Every matcher also available in form of method. # # 'Mary'.should().match /ry/ # 'Mary'.should().be 'Mary' # 'Mary'.should().contain 'ry' # 'Mary'.should().beEqualTo 'Mary' # # 10.should().beGreaterThan 9 # # fun = -> throw 'some bug' # (-> fun()).should().throw 'some bug' # # _(null).should().be null # # Mocks and stubs. # # class Bob # hi: -> 'hi' # # bob = new Bob() # bob.spyOn 'hi', andReturn: 'Hello' # bob.hi().should be: 'Hello' # bob.hi.should().haveBeenCalled() # # ### Control flow helpers. # # `it.async` and `it.next` helpers allows You to write asynchronous specs. `it.async` will pause # specs execution and will wait untill `it.next` will be called. # # it.async "should save object to collection", -> # db.collection 'units', (err, collection) -> # obj = name: 'Probe', status: 'alive' # collection.create obj, (err, result) -> # _(err).should be: null # it.next() # # `it.sync` helper designed to be used with fiber-aware code and wraps the spec inside # of [Fiber](https://github.com/laverdet/node-fibers), the previous sample will # looks like this. # # it.async "should save object to collection", -> # collection = db.collection 'units' # obj = name: 'Probe', status: 'alive' # collection.create obj # # In short, `it.sync` helps to write asynchrnous code as if it's synchronous. If You need more samples # please take a look at [Mongo Model](http://alexeypetrushin.github.com/mongo-model) all its # specs are writeen using `it.sync`. # # # ### Installation # # Node.JS `npm install mary` # # Broser `add jasmine.js and mary.js to the page` # # You can also use Dr. Marys's own spec as a sample, run it with `cake spec` and see the result. # # Dr. Mary is a thin wrapper around the [Jasmine](http://pivotal.github.com/jasmine) and # [jasmine-node](https://github.com/mhevery/jasmine-node) libraries. # # The project is [hosted on GitHub](https://github.com/alexeypetrushin/mary), You can report bugs and discuss features # on the [issues page](https://github.com/alexeypetrushin/mary/issues). # # Copyright (c) Alexey Petrushin [http://petrush.in](http://petrush.in), released under the MIT license. # ### Source Code # Checking for presence of Jasmine. throw new Error("no jasmine (mary requires jasmine BDD framework)!") unless jasmine? # Adding some useful matchers to Jasmine. jasmine.Matchers.prototype.toInclude = (expected) -> if @actual.indexOf @actual.indexOf(expected) >= 0 else expected of @actual jasmine.Matchers.prototype.toInclude = jasmine.Matchers.matcherFn_( 'toInclude', jasmine.Matchers.prototype.toInclude ) # Mary. Mary = {} # Matcher. class Mary.Matcher constructor: (@obj) -> @expect = expect obj # Expectations with expected value. include : (o) -> @expect.toInclude o beEqualTo : (o) -> @expect.toEqual o be : (o) -> @expect.toEqual o match : (o) -> @expect.toMatch o contain : (o) -> @expect.toContain o beLessThan : (o) -> @expect.toBeLessThan o beGreaterThan : (o) -> @expect.toBeGreaterThan o throw : (o) -> @expect.toThrow o raise : (o) -> @expect.toThrow o # Expectations without expected value. beNull : () -> @expect.toBeNull() beTrue : () -> @expect.toBeTruthy() beFalse : () -> @expect.toBeFalsy() beDefined : () -> @expect.toBeDefined() beUndefined : () -> @expect.toBeUndefined() # Stubs and mocks. haveBeenCalled : () -> @expect.toHaveBeenCalled() haveBeenCalledWith : (args...) -> @expect.toHaveBeenCalledWith.apply(@expect, args) # Apply matchers defined as hash, i.e. `be: null`. applyHashMatchers: (args) -> if args then for matcher, value of args @[matcher](value) @ # Negative matcher. class Mary.NegativeMatcher extends Mary.Matcher constructor: (@obj) -> @expect = expect(obj).not # `should` and `shouldNot` methods. getValue = (obj) -> if obj.hasOwnProperty('_wrapped') obj._wrapped else obj.valueOf() methods = should: (args) -> new Mary.Matcher(getValue(@)).applyHashMatchers(args) shouldNot: (args) -> new Mary.NegativeMatcher(getValue(@)).applyHashMatchers(args) spyOn: (method, options) -> spy = spyOn(getValue(@), method) if options then for method, arg of options spy[method](arg) spy # Extending native types with `should` methods. types = [ Object.prototype String.prototype Number.prototype Array.prototype Boolean.prototype Date.prototype Function.prototype RegExp.prototype ] for type in types for name, method of methods Object.defineProperty type, name, enumerable: false writable: true configurable: true value: method # It's impossible to extend `null` and `undefined`, # so we use a wrapper, i.e. `_(null).shouldBe().undefined()`. # # Sometimes such wrapper may be already defined (by underscore.js # for example), if it's not we defining it. wrapper = (obj) -> wrapper = new Object() wrapper._wrapped = obj wrapper # Flow. # # Sample: # # it.async "should provide handy shortcuts to databases", -> # $db.collection 'test', (err, collection) -> # collection.name.should be: 'test' # it.next() # # Block and waits untill `it.next()` is called. it.async = (desc, func) -> it desc, -> it.finished = false func() waitsFor (-> it.finished), desc, 1000 # Resumes execution of `it.async`. it.next = (e) -> it.lastError = e it.finished = true # Wraps spec into Fiber. it.sync = (desc, callback) -> try require 'fibers' catch e console.log """ WARN: You are trying to use synchronous mode. Synchronous mode is optional and requires additional `fibers` library. It seems that there's no such library in Your system. Please install it with `npm install fibers`.""" throw e it.async desc, -> Fiber(-> callback() it.next() ).run() # Setting up globals. if module? and module.exports? exports.Mary = Mary exports._ = wrapper if window? window.Mary = Mary window._ ||= wrapper