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