├── .gitignore ├── LICENSE ├── Readme.md ├── cakes.coffee ├── examples └── test.coffee ├── index.js ├── package.json └── test └── cakes.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | node_modules 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2011-2012 Quang Van 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Project is In-Active 2 | 3 | Checkout [mocha-cakes-2](https://github.com/iensu/mocha-cakes-2) 4 | 5 | 6 | # What is it? 7 | 8 | [Gherkin](https://github.com/cucumber/cucumber/wiki/Gherkin)-[Cucumber](http://cukes.info/) syntax add-on for [mocha](https://github.com/visionmedia/mocha) javascript/node test framework for customer acceptance testing. 9 | 10 | Provides high-level/functional/acceptance test organization lingo, using _'Feature'_, _Stories_, _'Scenarios'_, _'Given/Then/When'_. 11 | 12 | ![Mocha-Cakes Pretty Output](http://i.imgur.com/cKUO8.png) 13 | 14 | # Mocha-Cakes Commands 15 | 16 | Mocha-Cakes adds the following commands: 17 | 18 | `Feature` 19 | `Scenario` 20 | 21 | `Given` 22 | `When` 23 | `Then` 24 | 25 | `And` 26 | `But` 27 | `I` 28 | 29 | `System` 30 | `Describe` 31 | 32 | You can use these commands to describe your tests & specs, as well as mocha's BDD commands `describe`, `it`, `before`, `beforeEach`, `after`, `afterEach` OR mocha's TDD commands `suite`, `test`, `setup`, `teardown`, `suiteSetup`, `suiteTeardown` 33 | 34 | # Mocha-Cakes Commands Breakdown 35 | 36 | Mocha-Cakes extends Mocha, by adding on helpful commands and print-outs for Acceptance Tests. (Given, When, Then, etc.) 37 | 38 | ##Acceptance Tests 39 | 40 | `Feature`, `Scenario` (maps to _describe_) 41 | 42 | `Given`, `When`, `Then` (maps to _it_, but if first message argument is ommited, it'll be a _describe_) 43 | 44 | `And`, `But`, `I` (maps to _it_ but if first message argument is ommited, it'll be a _describe_) 45 | 46 | ### GWTab 47 | GWTab commands can map to a describe if the message argument is ommited. 48 | 49 | ```coffeescript 50 | Given 'I am at home', -> # it's an it 51 | home.should.eql 'home' 52 | 53 | Given -> # it's a describe 54 | it 'is dark', -> 55 | outside.should.eql 'dark' 56 | ``` 57 | 58 | ## Grey-Box, System Tests 59 | 60 | `System` (if it has a message it'll be an _it_, if not it'll be a _describe_ with System label, useful for testing (grey box) system resources, database, not directly observable by Customer etc.) 61 | 62 | ```coffeescript 63 | Given -> 64 | System 'Logged Out', -> 65 | 66 | Then -> 67 | System -> 68 | it 'should log in', -> 69 | ``` 70 | 71 | ## Pretty Commands for Specs/Unit Tests 72 | 73 | `Describe` (maps to _describe_ used for things like filenames) 74 | 75 | ```coffeescript 76 | Describe 'lib/file.coffee' # filename 77 | describe '+copy()', -> 78 | it 'should copy files...', -> 79 | ``` 80 | 81 | ## Custom 82 | 83 | Mocha-Cakes 0.7 added the `I` command, to do things like: 84 | 85 | ``` 86 | Given -> 87 | I 'have a test', -> 88 | And 'I have another', -> 89 | Then -> 90 | I 'should be good', -> 91 | But 'make sure I am also', -> 92 | ``` 93 | 94 | # Example 95 | 96 | _Coffee-Script: test.coffee_ 97 | 98 | ```coffeescript 99 | 100 | require 'mocha-cakes' 101 | 102 | Feature "New Feature", 103 | "In order to use cool feature", 104 | "as a new user", 105 | "I want do include this", -> 106 | 107 | Scenario "Singing", -> 108 | 109 | voice = null 110 | 111 | Given "I am a good singing", -> 112 | When "I sing", -> 113 | voice = 'good' 114 | Then "it should sound good", -> 115 | voice.should.eql 'good' 116 | 117 | ``` 118 | 119 | Run this test using mocha command: 120 | 121 | `mocha test.coffee -R spec -r should --compilers coffee:coffee-script` 122 | 123 | # What's going on? 124 | 125 | Mocha-cakes gives you access to function names 126 | 127 | _"Feature", "Scenario"_ that wraps around mocha's `describe()`. 128 | 129 | _"Given", "When", "Then", "And", "But"_ wraps around mocha's `it()`. (If first argument is omitted `Given ->` it'll be a `describe()`) 130 | 131 | Also bonus, "Describe" wraps around mocha's _describe()_ also, that could be used at the start of spec files. It prints out in bolded blue header with `-R Spec`. And `System()` is a _describe_ or _it_ depending on if first argument is a string or callback. 132 | 133 | So the above would output something like: 134 | 135 | ```cucumber 136 | Feature: New Feature 137 | 138 | In order to use cool feature 139 | as a new user 140 | I want do include this 141 | 142 | Scenario: Singing 143 | ✓ Given: I am a good singing 144 | ✓ When: I sing 145 | ✓ Then: it should sound good 146 | ✓ sound good 147 | 148 | 149 | ✔ 1 tests complete (3ms) 150 | 151 | ``` 152 | 153 | ## How to Use 154 | 155 | Mocha-Cakes provides GWT commands to mocha, and pretty prints it. 156 | 157 | To use just: 158 | 159 | 1. require 'mocha-cakes' 160 | 161 | Then you will have access to the mocha-cakes commands _Feature, Scenario, Given, When, Then, etc._ 162 | 163 | Also to _see_ the pretty output, use the _spec_ reporter 164 | 165 | `mocha acceptance_tests.coffee -R spec -r mocha-cakes --compilers coffee:coffee-script` 166 | 167 | Note: You can use mocha-cakes with plain javascript. 168 | 169 | ## Features 170 | 171 | ```coffeescript 172 | 173 | require 'mocha-cakes' 174 | 175 | Feature "Big Buttons", 176 | "As a user", 177 | "I want big buttons", 178 | "So it'll be easier to use", -> 179 | 180 | Scenario "On Homepage", -> 181 | 182 | Given "I am a new user", -> 183 | When "I go to homepage", -> 184 | 185 | And "I scroll down", -> 186 | Then "I see big buttons", -> 187 | But "no small text", -> 188 | 189 | Given -> # Describe 190 | When "I scroll down more", -> 191 | And "I reach end of page", -> 192 | Then "all I see is big buttons", -> 193 | 194 | Describe 'test.spec.coffee', -> 195 | 196 | Scenario false, 'Skip Me', -> 197 | 198 | ``` 199 | 200 | _\* Remember, they're all either `describe()`'s or `it()`_ 201 | 202 | ## Mix & Match 203 | 204 | Also you could still mix-in regular mocha syntax 205 | 206 | ``` 207 | Feature "Mix & Match" -> 208 | Scenario 'Mix-in Mocha', -> 209 | Given "I'm using Mocha-Cakes", -> 210 | Then -> 211 | describe 'Also using regular mocha', -> 212 | I 'should be able to do this', -> 213 | true.should.be true 214 | it 'should work too', -> 215 | true.should.be true 216 | ``` 217 | 218 | Note you can also test asynchronous code with Mocha-Cakes passing a callback argument to any GWTabi command. (`done` for example) 219 | 220 | ``` 221 | Feature "Async tests with Mocha-Cakes", -> 222 | Given "I want to test async code", -> 223 | When "I pass 'done' to GWT commands", -> 224 | Then "It should wait for 'done' to be done.", (done)-> 225 | done() 226 | ``` 227 | 228 | ## Reference 229 | 230 | [The WHY behind TDD/BDD and the HOW with RSpec](http://www.slideshare.net/bmabey/the-why-behind-tddbdd-and-the-how-with-rspec) 231 | 232 | 233 | # Use it 234 | 235 | Install: 236 | 237 | cd my_project 238 | npm install --save-dev mocha-cakes 239 | 240 | # Mocha Reporter Support 241 | 242 | Mocha-Cakes was developed with the `-R spec` in mind. 243 | 244 | You can use Mocha-Cakes also with the `-R doc` reporter. 245 | 246 | All other reporters should function, but have not been tested. 247 | 248 | 249 | If you have any questions, issues or comments, please leave them on [mocha-cakes' github](https://github.com/quangv/mocha-cakes/issues). 250 | 251 | Thanks! 252 | 253 | --- 254 | 255 | \*Special Thanks\* to [TJ Holowaychuk](https://github.com/visionmedia) for Mocha, awesome test framework. 256 | -------------------------------------------------------------------------------- /cakes.coffee: -------------------------------------------------------------------------------- 1 | colors = require 'colors' 2 | _ = require 'underscore' 3 | _.str = require 'underscore.string' 4 | _.mixin _.str.exports() 5 | 6 | {argv} = require 'optimist' 7 | 8 | if argv.R == 'doc' # No colors for doc reporter. 9 | colors.mode = 'none' 10 | SPEC_REPORTER = 'doc' 11 | 12 | class MochaInterface # Support for Mocha BDD&TDD Interfaces 13 | _describe : 'describe' 14 | _it : 'it' 15 | 16 | constructor : -> 17 | # TDD Interface support 18 | argv.ui = argv.ui ? argv.u # mocha option --ui overwrites -u 19 | if argv.ui && (argv.ui == 'tdd' or _.last(argv.ui) == 'tdd') 20 | @_describe = 'suite' 21 | @_it = 'test' 22 | 23 | describe : -> 24 | global[@_describe].apply global, arguments 25 | it : -> 26 | global[@_it].apply global, arguments 27 | 28 | mocha = new MochaInterface 29 | 30 | ### Start of Feature ### 31 | 32 | createFeature = (options)-> 33 | 34 | # Options = 35 | # label 36 | # whitespace 37 | # style 38 | 39 | return (feature, story..., callback)-> 40 | # exp. Feature 'new feature', 'in order to do good', 'as a user', 'I want to do good', -> 41 | 42 | if 'label' in options 43 | feature = 'Feature: '+feature 44 | 45 | if 'whitespace' in options 46 | feature = feature+'\n' 47 | 48 | if 'style' in options 49 | feature = feature.green.underline.bold 50 | 51 | message = feature+'\n' 52 | unless typeof story[0] is 'function' 53 | (message += '\t'+part+'\n' for part in story) 54 | else 55 | callback = story[0] 56 | 57 | mocha.describe message, callback 58 | 59 | exports.Feature = createFeature(['label', 'whitespace', 'style']) 60 | 61 | ### Start of Scenario ### 62 | 63 | createScenario = (options)-> 64 | 65 | # Options = 66 | # label 67 | # whitespace 68 | # style 69 | 70 | return (message, callback)-> 71 | 72 | if message == false # First arg is false, skip 73 | message = callback 74 | return skipScenario message, options 75 | 76 | if 'label' in options 77 | message = 'Scenario: '+message 78 | if 'whitespace' in options 79 | message = '\n '+message 80 | if 'style' in options 81 | message = message.green 82 | 83 | mocha.describe message, callback 84 | 85 | skipScenario = (message, options)-> 86 | if 'label' in options 87 | message = '(skipped) ' + message 88 | if 'whitespace' in options 89 | message = '\n '+message 90 | if 'style' in options 91 | message = message.yellow.bold 92 | 93 | mocha.describe message, -> 94 | 95 | exports.Scenario = createScenario(['whitespace', 'label', 'style']) 96 | 97 | 98 | ### Beginning of GWTab ### 99 | 100 | describeItNest = (command, message, callback, options)-> # nest commands inside a Describe so mixed describe/its will line up on spec output. 101 | label = nestLabel options # get pretty labels for nest. 102 | mocha.describe label, -> 103 | if command == 'it' 104 | mocha.it message, callback 105 | else 106 | mocha.describe '', -> 107 | mocha.describe message, callback 108 | 109 | nestLabel = (options)-> # returns label of nested describes/its 110 | label = '' 111 | if 'label' in options 112 | label = '◦' 113 | if 'style' in options 114 | if 'dark' in options 115 | label = label.black 116 | else 117 | label = label.green 118 | 119 | if SPEC_REPORTER == 'doc' 120 | label = '' 121 | 122 | return label 123 | 124 | isPending = (command, message, cb)-> # Return Pending message. 125 | if not cb or cb.toString() == (->).toString() # If Blank 126 | command = 'it' # Convert pendings to It 127 | message = '◊ '+_.clean(message.stripColors)+' (pending)' 128 | cb = null 129 | return [command, message, cb] 130 | 131 | gwtItDescribe = (label, message, callback, options)-> # routes command to a Describe or an It 132 | # If it's not passed a message, it'll be describe. 133 | if typeof message == 'function' 134 | callback = message 135 | message = label 136 | command = 'describe' 137 | else # It's an it 138 | message = label+message 139 | command = 'it' 140 | 141 | [command, message, callback] = isPending(command, message, callback) 142 | 143 | describeItNest command, message, callback, options 144 | 145 | 146 | createGWTab = (label, options)-> # Creates Given, When, Then, and, but commands 147 | return (message, callback)-> 148 | label = gwtLabel label, options 149 | gwtItDescribe label, message, callback, options 150 | 151 | gwtLabel = (label, options)-> # Returns pretty GWTab labels 152 | if 'label' in options 153 | if label && ('style' in options) 154 | if 'dark' in options 155 | label = label.grey 156 | else if 'white' in options 157 | label = label.white 158 | else 159 | label = label.yellow 160 | else 161 | label = '' 162 | 163 | return label 164 | 165 | 166 | exports.Given = createGWTab('Given: ', ['label', 'style']) 167 | 168 | exports.When = createGWTab(' When: ', ['label', 'style']) 169 | 170 | exports.Then = createGWTab(' Then: ', ['label', 'style']) 171 | 172 | exports.And = createGWTab(' And: ', ['label', 'style', 'dark']) 173 | 174 | exports.But = createGWTab(' But: ', ['label', 'style', 'dark']) 175 | 176 | exports.I = createGWTab(' I ', ['label', 'style', 'white']) 177 | 178 | ### End of GWTab ### 179 | ### Start of Describe ### 180 | 181 | createDescribe = (options)-> 182 | return (message, callback)-> 183 | if 'label' in options 184 | message = "=== #{message} ===" 185 | 186 | if 'style' in options 187 | message = message.blue 188 | 189 | mocha.describe message, callback 190 | 191 | exports.Describe = createDescribe(['label', 'style']) 192 | 193 | createSystem = (options)-> 194 | return (msg, callback)-> 195 | label = '' 196 | if 'label' in options 197 | label = '[system]' 198 | 199 | if 'style' in options 200 | label = label.black.italic 201 | 202 | # If it has a message, it's an IT, or else it's a describe. 203 | if typeof msg is 'function' # No msg, so it's a describe 204 | callback = msg 205 | msg = '' 206 | [command, msg, callback] = isPending('describe', msg, callback) 207 | else 208 | [command, msg, callback] = isPending('it', msg, callback) 209 | 210 | if 'style' in options and callback is null # isPending 211 | msg = msg.cyan 212 | 213 | label += ' '+msg 214 | describeItNest command, label, callback, options 215 | 216 | 217 | exports.System = createSystem(['label', 'style']) 218 | 219 | # Add function names to global scope. 220 | (global[name] = func for name, func of module.exports) 221 | -------------------------------------------------------------------------------- /examples/test.coffee: -------------------------------------------------------------------------------- 1 | require '../' 2 | 3 | Feature "New Feature", 4 | "In order to use cool feature", 5 | "as a new user", 6 | "I want do include this", -> 7 | 8 | Scenario "Singing", -> 9 | 10 | voice = null 11 | 12 | Given "I am a good singing", -> 13 | it 'should be true', -> 14 | true.should.eql true 15 | 16 | it 'should be true too', -> 17 | true.should.eql true 18 | 19 | When "I sing", -> 20 | voice = 'good' 21 | Then "it should sound good", -> 22 | voice.should.eql 'good' 23 | 24 | And "it should do this", -> 25 | But "it shouldn't do that", -> 26 | 27 | Describe '/test/describe.spec', -> 28 | 29 | Given 'Test', -> 30 | true.should.eql true 31 | 32 | When -> 33 | it 'should be true', -> 34 | true.should.eql true 35 | Then 'Yup', -> 36 | true.should.eql true 37 | 38 | # Pendings 39 | 40 | Given "It's Pending", -> 41 | When -> 42 | Then -> 43 | 44 | Feature "Mix & Match", -> 45 | Scenario 'Mix-in Mocha', -> 46 | Given "I'm using Cakes", -> 47 | Then -> 48 | describe 'Also using regular mocha', -> 49 | I 'should be able to do this', -> 50 | true.should.eql true 51 | it 'should work too', -> 52 | true.should.eql true 53 | 54 | Feature "Async tests with Mocha-Cakes", -> 55 | Given "I want to test async code", -> 56 | When "I pass 'done' to GWT commands", -> 57 | Then "It should wait for 'done' to be done.", (done)-> 58 | done() 59 | 60 | # Run with 61 | # mocha examples/test.coffee -R spec -r should 62 | # 63 | # note: must have should installed in mocha for above example to work 64 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('coffee-script'); 2 | module.exports = require('./cakes.coffee'); 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { "name" : "mocha-cakes" 2 | , "description" : "bdd stories add-on for mocha test framework with cucumber given/then/when syntax." 3 | , "version" : "0.9.0" 4 | , "author" : "Quang Van " 5 | , "homepage" : "https://github.com/quangv/mocha-cakes" 6 | , "repository" : { "type": "git", "url": "git://github.com/quangv/mocha-cakes.git"} 7 | , "dependencies" : { "coffee-script" : "*" 8 | ,"colors" : "*" 9 | ,"underscore" : "*" 10 | ,"optimist" : "*" 11 | ,"underscore.string" : "*" 12 | } 13 | , "devDependencies" : { "mocha" : "*" 14 | ,"should" : "*" 15 | } 16 | , "keywords" : ["mocha", "bdd", "stories", "cucumber", "test", "testing", "gherkin", "acceptance", "customer", "functional", "end-user"] 17 | , "main" : "./index.js" 18 | } 19 | -------------------------------------------------------------------------------- /test/cakes.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | Mocha-Cakes Test Suite 3 | ### 4 | 5 | describe '#Feature()', -> 6 | describe '#Scenario()', -> 7 | 8 | describe '#Given()', -> 9 | describe '#When()', -> 10 | describe '#Then()', -> 11 | 12 | describe '#Given_()', -> 13 | describe '#When_()', -> 14 | describe '#Then_()', -> 15 | 16 | describe '#And()', -> 17 | describe '#But()', -> 18 | 19 | describe '#Describe()', -> 20 | --------------------------------------------------------------------------------