├── .gitignore ├── .jshintrc ├── Gruntfile.js ├── LICENSE-MIT ├── README.md ├── build.js ├── cuke-browser-watcher.js ├── cuke-watcher.js ├── features ├── add-item-view.feature ├── add-item.feature ├── step_definitions │ ├── add-item-view.steps.js │ ├── add-item.steps.js │ └── background-open-application.steps.js └── support │ └── world.js ├── gulpfile.js ├── karma.conf.js ├── package.json ├── script ├── app.js └── model │ └── grocery-list.js ├── template ├── app-main.us ├── testrunner-wrapper.us └── wrapper.us ├── test ├── addItemSteps.js ├── addItemViewSteps.js ├── backgroundOpenApplicationSteps.js ├── cucumber-testrunner.html ├── features.js ├── lib │ └── cucumber.js ├── script │ ├── app.js │ └── tap-listener.js └── world.js └── testem.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | *.sublime* 4 | node_modules 5 | build -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": "nofunc", 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": true, 11 | "boss": true, 12 | "eqnull": true, 13 | "node": true 14 | } -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 'use strict'; 3 | 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | watch: { 7 | cucumber: { 8 | files: ['features/**/*.js', 'script/**/*.js'], 9 | tasks: ['cucumberjs'] 10 | } 11 | }, 12 | cucumberjs: { 13 | src: 'features', 14 | options: { 15 | steps: 'features/step_definitions', 16 | format: 'pretty' 17 | } 18 | } 19 | }); 20 | 21 | grunt.loadNpmTasks('grunt-contrib-watch'); 22 | grunt.loadNpmTasks('grunt-cucumber'); 23 | 24 | grunt.registerTask('watch-tests', 'Starts a watch for test automation.', ['watch:cucumber']); 25 | 26 | }; -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Todd Anderson 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cucumberjs-examples 2 | =================== 3 | 4 | > Source for post series: [BDD in JavaScript: CucumberJS](http://custardbelly.com/blog/blog-posts/2014/01/08/bdd-in-js-cucumberjs/index.html) 5 | 6 | [![browser support](https://ci.testling.com/bustardcelly/cucumberjs-examples.png)](https://ci.testling.com/bustardcelly/cucumberjs-examples) 7 | 8 | 9 | Selenium Tests Status 10 | 11 | 12 | Requirements 13 | === 14 | 15 | ## Node & NPM 16 | 17 | Once [installed](http://www.joyent.com/blog/installing-node-and-npm/), run: 18 | 19 | ``` 20 | $ npm install 21 | ``` 22 | 23 | Tasks 24 | === 25 | 26 | ## Test 27 | 28 | Runs basic [cucumberjs](https://github.com/cucumber/cucumber-js) cli tool. 29 | 30 | ``` 31 | $ npm run test 32 | ``` 33 | 34 | ## Watch 35 | 36 | Runs basic file watch to automate [cucumberjs](https://github.com/cucumber/cucumber-js) cli tool 37 | 38 | ``` 39 | $ npm run watch 40 | ``` 41 | 42 | ## Watch-Browser 43 | 44 | Runs [cucumberjs-browser](https://github.com/bustardcelly/cucumberjs-browser) cuke bundler to run [cucumberjs](https://github.com/cucumber/cucumber-js) tool in browser! 45 | 46 | ``` 47 | $ npm run watch-browser 48 | ``` 49 | 50 | ## Build 51 | 52 | Build the app for to live in the wild. 53 | 54 | ``` 55 | $ npm run build 56 | ``` 57 | 58 | License 59 | === 60 | Copyright (c) 2014 Todd Anderson 61 | 62 | Permission is hereby granted, free of charge, to any person 63 | obtaining a copy of this software and associated documentation 64 | files (the "Software"), to deal in the Software without 65 | restriction, including without limitation the rights to use, 66 | copy, modify, merge, publish, distribute, sublicense, and/or sell 67 | copies of the Software, and to permit persons to whom the 68 | Software is furnished to do so, subject to the following 69 | conditions: 70 | 71 | The above copyright notice and this permission notice shall be 72 | included in all copies or substantial portions of the Software. 73 | 74 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 75 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 76 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 77 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 78 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 79 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 80 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 81 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var map = require('map-stream'); 5 | var tmpl = require('lodash.template'); 6 | var browserify = require('browserify'); 7 | var mkdirp = require('mkdirp'); 8 | 9 | var output = process.cwd() + '/build'; 10 | 11 | var wrap = function(wrapperTemplate) { 12 | return map(function(file, cb) { 13 | var content = file.toString(); 14 | fs.readFile(path.resolve(wrapperTemplate), 'utf8', function(err, filedata) { 15 | cb(null, tmpl(filedata, {yield:content})); 16 | }); 17 | }); 18 | }; 19 | 20 | var bundleApp = function(callback) { 21 | browserify(process.cwd() + '/script/app.js') 22 | .bundle({ 23 | standalone: 'app' 24 | }) 25 | .pipe(fs.createWriteStream(output + '/script/app.js')) 26 | .on('close', function() { 27 | if(callback) { 28 | callback(); 29 | } 30 | }); 31 | }; 32 | 33 | var templateApp = function(callback) { 34 | fs.createReadStream(process.cwd() + '/template/app-main.us') 35 | .pipe(wrap(process.cwd() + '/template/wrapper.us')) 36 | .pipe(fs.createWriteStream(output + '/index.html')) 37 | .on('close', function() { 38 | if(callback) { 39 | callback(); 40 | } 41 | }); 42 | }; 43 | 44 | mkdirp.sync(output + '/script'); 45 | bundleApp(templateApp); -------------------------------------------------------------------------------- /cuke-browser-watcher.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var map = require('map-stream'); 5 | var tmpl = require('lodash.template'); 6 | var watch = require('node-watch'); 7 | var child_process = require('child_process'); 8 | var mkdirp = require('mkdirp'); 9 | var rimraf = require('rimraf'); 10 | var browserify = require('browserify'); 11 | 12 | var http = require('http'); 13 | var tinylr = require('tiny-lr'); 14 | var connect = require('connect'); 15 | var open = require('open'); 16 | var S = require('string'); 17 | 18 | var tempdir = '.tmp'; 19 | var outdir = 'test'; 20 | var browserCukes; 21 | 22 | var livereloadPort = 35729; 23 | var connectPort = 8080; 24 | var JS_EXT = /^.*\.js/i; 25 | var options = ['-f', 'tap', 26 | '-o', outdir, 27 | '--tmpl', tempdir + '/testrunner.html']; 28 | 29 | var wrap = function(wrapperTemplate) { 30 | return map(function(file, cb) { 31 | var content = file.toString(); 32 | fs.readFile(path.resolve(wrapperTemplate), 'utf8', function(err, filedata) { 33 | cb(null, filedata.replace(/[^]<%= yield %>/i, content)); 34 | }); 35 | }); 36 | }; 37 | 38 | // [TASKS] 39 | // a. re-bundle the app. 40 | var bundleApplication = function(f, callback) { 41 | return function() { 42 | browserify(__dirname + '/script/app.js') 43 | .bundle({ 44 | standalone: 'app' 45 | }) 46 | .pipe(fs.createWriteStream(path.resolve(outdir + '/script/app.js'))) 47 | .on('close', function() { 48 | console.log('changed app.js...'); 49 | if(callback) { 50 | callback(); 51 | } 52 | }); 53 | }; 54 | }; 55 | // b. template testrunner with app partial. 56 | var templateTestRunner = function(callback) { 57 | fs.createReadStream(__dirname + '/template/app-main.us') 58 | .pipe(wrap(__dirname + '/template/testrunner-wrapper.us')) 59 | .pipe(fs.createWriteStream(path.resolve(tempdir + '/testrunner.html'))) 60 | .on('close', function() { 61 | if(callback) { 62 | callback(); 63 | } 64 | }); 65 | }; 66 | // c. rerun cucumberjs-browser tool. 67 | var cuke = function(f, callback) { 68 | return function() { 69 | var filename = S(path.basename(f, '.js').split('.').join('-')).camelize().s; 70 | templateTestRunner(function() { 71 | browserCukes = child_process.spawn('cucumberjs-browser', options) 72 | .on('exit', function() { 73 | console.log('changed ' + filename + '...'); 74 | rimraf(tempdir, function() { 75 | if(callback) { 76 | callback(); 77 | } 78 | }); 79 | }); 80 | }); 81 | }; 82 | }; 83 | 84 | // 1. Recursive mkdir /test/script if not exist. 85 | mkdirp.sync(outdir + '/script'); 86 | mkdirp.sync(tempdir); 87 | 88 | // 2. Create tiny-livereload server. 89 | var lr = tinylr(); 90 | lr.listen(livereloadPort, function() { 91 | console.log('livereload listening on ' + livereloadPort + '...'); 92 | }); 93 | 94 | // 3. Start server on localhost. 95 | var app = connect().use(connect.static(__dirname + '/test')); 96 | var server = http.createServer(app).listen(connectPort, function() { 97 | console.log('local server started on ' + connectPort + '...'); 98 | console.log('Note: Remember to start the livereload browser extension!'); 99 | console.log('http://feedback.livereload.com/knowledgebase/articles/86242-how-do-i-install-and-use-the-browser-extensions-'); 100 | cuke('./features/support/world', function() { 101 | bundleApplication('./script/app.js', function() { 102 | open('http://localhost:' + connectPort + '/cucumber-testrunner.html'); 103 | })(); 104 | })(); 105 | }); 106 | 107 | // 4. Watch source and generate bundles. 108 | watch(['./features', './script'], {recursive:true}, function(filename) { 109 | // Used to resolve when running operation(s) are complete. 110 | var resolver; 111 | var running = false; 112 | var resolveWatch = function(limit) { 113 | var count = 0; 114 | running = true; 115 | return function() { 116 | if(++count === limit) { 117 | count = 0; 118 | running = false; 119 | } 120 | else { 121 | running = true; 122 | } 123 | }; 124 | }; 125 | 126 | if(!running && filename.match(JS_EXT)) { 127 | var bundleAppInvoke = bundleApplication(filename, function() { 128 | lr.changed({ 129 | body: { 130 | files: ['script/app'] 131 | } 132 | }); 133 | resolver(); 134 | }); 135 | if(/^script?/i.test(filename)) { 136 | resolver = resolveWatch(1); 137 | bundleAppInvoke(); 138 | } 139 | else if(/^features?/i.test(filename)) { 140 | resolver = resolveWatch(2); 141 | cuke(filename, function() { 142 | lr.changed({ 143 | body: { 144 | files: [filename] 145 | } 146 | }); 147 | resolver(); 148 | bundleAppInvoke(); 149 | })(); 150 | } 151 | } 152 | 153 | }); -------------------------------------------------------------------------------- /cuke-watcher.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var watch = require('node-watch'); 3 | var child_process = require('child_process'); 4 | var running = false; 5 | var cucumber; 6 | 7 | var JS_EXT = /^.*\.js/i; 8 | var options = ['node_modules/.bin/cucumber-js', 9 | 'features', 10 | '-r', 'features/step_definitions', 11 | '-f', 'pretty']; 12 | 13 | watch(['./features/step_definitions', './script'], {recursive:true}, function(filename) { 14 | 15 | if(!running && filename.match(JS_EXT)) { 16 | 17 | running = true; 18 | 19 | cucumber = child_process.spawn('node', options) 20 | .on('exit', function() { 21 | running = false; 22 | }); 23 | 24 | cucumber.stdout.on('data', function(d) { 25 | console.log(String(d)); 26 | }); 27 | 28 | cucumber.stderr.on('data', function(d) { 29 | console.error(String(d)); 30 | }); 31 | 32 | } 33 | 34 | }); -------------------------------------------------------------------------------- /features/add-item-view.feature: -------------------------------------------------------------------------------- 1 | Feature: Shopper can add and view new item in Grocery List 2 | As a shopper using the browser-based app 3 | I want to add an item to my grocery list view 4 | So that I can remember to buy that item at the grocery store 5 | 6 | Background: Grocery List Application is Open 7 | Given I have opened the grocery list application 8 | 9 | Scenario: Submit of valid item adds item to list 10 | Given I have an empty grocery list view 11 | When I provide a valid grocery list item name 12 | And I select to add an item 13 | Then The item is added to the grocery list view 14 | 15 | Scenario: Submit of valid item adds item to collection 16 | Given I have an empty grocery list view 17 | When I provide a valid grocery list item name 18 | And I select to add an item 19 | Then The item is accessible from the grocery list collection -------------------------------------------------------------------------------- /features/add-item.feature: -------------------------------------------------------------------------------- 1 | Feature: Shopper can add an item to their Grocery List 2 | As a shopper 3 | I want to add an item to my grocery list 4 | So that I can remember to buy that item at the grocery store 5 | 6 | Background: Grocery List Application is Open 7 | Given I have opened the grocery list application 8 | 9 | Scenario: Item added to grocery list 10 | Given I have an empty grocery list 11 | When I add an item to the list 12 | Then The grocery list contains a single item 13 | 14 | Scenario: Item accessible from grocery list 15 | Given I have an empty grocery list 16 | When I add an item to the list 17 | Then I can access that item from the grocery list -------------------------------------------------------------------------------- /features/step_definitions/add-item-view.steps.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | module.exports = function() { 4 | 'use strict'; 5 | 6 | var enteredItem; 7 | 8 | this.World = require('../support/world').World; 9 | 10 | this.Given(/^I have an empty grocery list view$/, function(callback) { 11 | this.emptyGroceryListView(); 12 | assert.equal(this.getGroceryListView().childNodes.length, 0); 13 | callback(); 14 | }); 15 | 16 | this.When(/^I provide a valid grocery list item name$/, function(callback) { 17 | enteredItem = this.createGroceryItem(); 18 | this.enterNewGorceryListItem(enteredItem); 19 | callback(); 20 | }); 21 | 22 | this.When(/^I select to add an item$/, function(callback) { 23 | this.clickAddGroceryListItem(); 24 | callback(); 25 | }); 26 | 27 | this.Then(/^The item is added to the grocery list view$/, function(callback) { 28 | assert.equal(this.getGroceryListViewItemAtIndex(0), enteredItem, 'Entered item should be first in empty list.'); 29 | callback(); 30 | }); 31 | 32 | this.Then(/^The item is accessible from the grocery list collection$/, function(callback) { 33 | assert.equal(this.groceryListApplication.list.getItemIndex(enteredItem), 0, 'Added item should be found at first index.'); 34 | callback(); 35 | }); 36 | 37 | }; -------------------------------------------------------------------------------- /features/step_definitions/add-item.steps.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assert = require('assert'); 3 | 4 | module.exports = function() { 5 | 6 | var listItem; 7 | 8 | this.World = require('../support/world').World; 9 | 10 | this.Given(/^I have an empty grocery list$/, function(callback) { 11 | this.groceryListApplication.list.empty(); 12 | callback(); 13 | }); 14 | 15 | this.When(/^I add an item to the list$/, function(callback) { 16 | listItem = this.createGroceryItem(); 17 | this.groceryListApplication.list.add(listItem); 18 | callback(); 19 | }); 20 | 21 | this.Then(/^The grocery list contains a single item$/, function(callback) { 22 | assert.equal(this.groceryListApplication.list.getAll().length, 1, 'Grocery List should grow by one item.'); 23 | callback(); 24 | }); 25 | 26 | this.Then(/^I can access that item from the grocery list$/, function(callback) { 27 | assert.notEqual(this.groceryListApplication.list.getItemIndex(listItem), -1, 'Added item should be found at non-negative index.'); 28 | callback(); 29 | }); 30 | 31 | }; -------------------------------------------------------------------------------- /features/step_definitions/background-open-application.steps.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assert = require('assert'); 3 | 4 | module.exports = function() { 5 | 6 | this.World = require('../support/world').World; 7 | 8 | this.Given(/^I have opened the grocery list application$/, function(callback) { 9 | (function(world) { 10 | world.domload(function() { 11 | world.groceryListApplication = world.openGroceryList(); 12 | assert(world.groceryListApplication, 'Grocery List Application is required to be open for editability.'); 13 | callback(); 14 | }); 15 | }(this)); 16 | }); 17 | 18 | }; -------------------------------------------------------------------------------- /features/support/world.js: -------------------------------------------------------------------------------- 1 | /*global window, document*/ 2 | 'use strict'; 3 | 4 | var World = function World(callback) { 5 | 6 | this.window = process.browser ? window : {}; 7 | this.app = undefined; 8 | this.groceryListApplication = undefined; 9 | 10 | var defineGlobals = function(w, doc) { 11 | this.app = w.app; 12 | }; 13 | 14 | this.domload = function(callback) { 15 | (function(world) { 16 | if(document.readyState === 'complete') { 17 | defineGlobals.call(world, window, document); 18 | callback(); 19 | } 20 | else { 21 | var delegate = document.addEventListener ? 'addEventListener' : 'attachEvent'; 22 | var eventType = document.addEventListener ? 'load' : 'onload'; 23 | window[delegate](eventType, function() { 24 | defineGlobals.call(world, window, document); 25 | callback(); 26 | }); 27 | } 28 | }(this)); 29 | }; 30 | 31 | this.openGroceryList = function() { 32 | return this.app.newSession(); 33 | }; 34 | this.createGroceryItem = function() { 35 | return 'apple'; 36 | }; 37 | 38 | this.getGroceryListView = function() { 39 | return this.groceryListApplication.$listview; 40 | }; 41 | 42 | this.getGroceryListViewItemAtIndex = function(index) { 43 | return this.groceryListApplication.$listview.childNodes[index].textContent; 44 | } 45 | 46 | this.emptyGroceryListView = function() { 47 | this.groceryListApplication.empty(); 48 | }; 49 | 50 | this.enterNewGorceryListItem = function(item) { 51 | this.groceryListApplication.enterNewItem(item); 52 | }; 53 | 54 | this.createClickEvent = function() { 55 | var event = document.createEvent('MouseEvents'); 56 | event.initEvent('click', true, false); 57 | return event; 58 | }; 59 | 60 | this.clickAddGroceryListItem = function() { 61 | var clickevent = this.createClickEvent(); 62 | this.groceryListApplication.$addbutton.dispatchEvent(clickevent); 63 | }; 64 | 65 | callback(); 66 | 67 | }; 68 | 69 | module.exports.World = World; -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var watch = require('gulp-watch'); 3 | var child_process = require('child_process'); 4 | 5 | var cucumber; 6 | var running = false; 7 | var options = ['node_modules/.bin/cucumber-js', 8 | 'features', 9 | '-r', 'features/step_definitions', 10 | '-f', 'pretty']; 11 | 12 | gulp.task('cucumber', function() { 13 | if(!running) { 14 | running = true; 15 | cucumber = child_process.spawn('node', options) 16 | .on('exit', function() { 17 | running = false; 18 | }); 19 | cucumber.stdout.on('data', function(d) { 20 | console.log(String(d)); 21 | }); 22 | 23 | cucumber.stderr.on('data', function(d) { 24 | console.error(String(d)); 25 | }); 26 | } 27 | }); 28 | 29 | gulp.task('watch-tests', function() { 30 | gulp.src(['features/**/*.js', 'script/**/*.js']) 31 | .pipe(watch(function() { 32 | gulp.run('cucumber'); 33 | })); 34 | }); -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | preprocessors: { 4 | '**/*.html': ['html2js'] 5 | }, 6 | 7 | files: [ 8 | '*.js', 9 | '*.html' 10 | ], 11 | 12 | browsers: ['Chrome'], 13 | 14 | reporters: ['dots'], 15 | 16 | plugins: [ 17 | 'karma-html2js-preprocessor', 18 | 'karma-chrome-launcher' 19 | ] 20 | }); 21 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cucumberjs-examples", 3 | "version": "0.5.1", 4 | "description": "Examples of using CucumberJS.", 5 | "author": { 6 | "name": "Todd Anderson", 7 | "email": "toddanderson@taanderson.com", 8 | "url": "http://custardbelly.com/blog" 9 | }, 10 | "keywords": [ 11 | "todd anderson", 12 | "cucumberjs", 13 | "bdd", 14 | "tdd" 15 | ], 16 | "homepage": "https://github.com/bustardcelly/cucumberjs-examples", 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/bustardcelly/cucumberjs-examples" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/bustardcelly/cucumberjs-examples/issues" 23 | }, 24 | "licenses": [ 25 | { 26 | "type": "MIT", 27 | "url": "https://github.com/bustardcelly/cucumberjs-examples/LICENSE-MIT" 28 | } 29 | ], 30 | "scripts": { 31 | "test": "node node_modules/.bin/cucumber-js", 32 | "watch": "node cuke-watcher.js", 33 | "watch-browser": "node cuke-browser-watcher", 34 | "build": "node build.js" 35 | }, 36 | "testling" : { 37 | "html" : "test/cucumber-testrunner.html", 38 | "browsers" : [ 39 | "ie/6..latest", 40 | "chrome/latest", 41 | "firefox/latest", 42 | "safari/latest", 43 | "iphone/6", "ipad/6" 44 | ] 45 | }, 46 | "devDependencies": { 47 | "cucumber": "~0.3.3", 48 | "node-watch": "~0.3.4", 49 | "grunt": "~0.4.2", 50 | "grunt-cucumber": "~0.2.3", 51 | "grunt-contrib-watch": "~0.5.3", 52 | "gulp": "~3.5.0", 53 | "gulp-watch": "~0.5.0", 54 | "karma-script-launcher": "~0.1.0", 55 | "karma-chrome-launcher": "~0.1.2", 56 | "karma-firefox-launcher": "~0.1.3", 57 | "karma-jasmine": "~0.1.5", 58 | "requirejs": "~2.1.10", 59 | "karma-requirejs": "~0.2.1", 60 | "karma-coffee-preprocessor": "~0.1.2", 61 | "karma-phantomjs-launcher": "~0.1.2", 62 | "karma": "~0.10.9", 63 | "karma-html2js-preprocessor": "~0.1.0", 64 | "browserify": "~3.28.1", 65 | "mkdirp": "~0.3.5", 66 | "tiny-lr": "0.0.5", 67 | "connect": "~2.12.0", 68 | "open": "0.0.4", 69 | "string": "~1.8.0", 70 | "map-stream": "~0.1.0", 71 | "rimraf": "~2.2.6", 72 | "lodash.template": "~2.4.1" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /script/app.js: -------------------------------------------------------------------------------- 1 | /*global document*/ 2 | 'use strict'; 3 | 4 | var GroceryList = require('./model/grocery-list'); 5 | 6 | var application = { 7 | init: function(list) { 8 | this.list = list; 9 | this.$listview = document.querySelector('#grocery-list'); 10 | this.$itemInputView = document.querySelector('#item-input'); 11 | this.$addbutton = document.querySelector('#add-button'); 12 | (function(app) { 13 | app.$addbutton.addEventListener('click', function(event) { 14 | var item = app.$itemInputView.value; 15 | app.addItemToView(item); 16 | app.list.add(item); 17 | }); 18 | }(this)); 19 | return this; 20 | }, 21 | empty: function() { 22 | var gl = this.$listview; 23 | while (gl.hasChildNodes()) { 24 | gl.removeChild(gl.lastChild); 25 | } 26 | this.list.empty(); 27 | }, 28 | enterNewItem: function(item) { 29 | this.$itemInputView.value = item; 30 | }, 31 | addItemToView: function(item) { 32 | var li = document.createElement('li'); 33 | var text = document.createTextNode(item); 34 | li.appendChild(text); 35 | this.$listview.appendChild(li); 36 | } 37 | }; 38 | 39 | module.exports = { 40 | newSession: function() { 41 | var newList = GroceryList.create(); 42 | return Object.create(application).init(newList); 43 | } 44 | }; -------------------------------------------------------------------------------- /script/model/grocery-list.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var groceryList = { 4 | empty: function() { 5 | this.list.length = 0; 6 | }, 7 | add: function(item) { 8 | this.list.push(item); 9 | }, 10 | getAll: function() { 11 | return this.list; 12 | }, 13 | getItemIndex: function(value) { 14 | var index = this.list.length; 15 | while(--index > -1) { 16 | if(this.list[index] === value) { 17 | return index; 18 | } 19 | } 20 | return -1; 21 | } 22 | }; 23 | 24 | module.exports = { 25 | create: function() { 26 | return Object.create(groceryList, { 27 | 'list': { 28 | value: [], 29 | writable: false, 30 | enumerable: true 31 | } 32 | }); 33 | } 34 | }; -------------------------------------------------------------------------------- /template/app-main.us: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 |
-------------------------------------------------------------------------------- /template/testrunner-wrapper.us: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <% if(listener.format === 'testem') { %> 7 | 8 | <% }; %> 9 | 10 | <% _.each(modules, function(module) { %> 11 | 12 | <% }); %> 13 | <% if(listener.exists) { %> 14 | 15 | <% }; %> 16 | <% if(listener.exists && /^ui?/i.test(listener.filename)) { %> 17 | 47 | <% }; %> 48 | 49 | 50 | 81 | <%= yield %> 82 | 83 | 84 | -------------------------------------------------------------------------------- /template/wrapper.us: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | cucumberjs example 6 | 7 | 8 | <%= yield %> 9 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /test/addItemSteps.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.addItemSteps=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the 'Software'), to 11 | // deal in the Software without restriction, including without limitation the 12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 13 | // sell copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | // when used in node, this will actually load the util module we depend on 27 | // versus loading the builtin util module as happens otherwise 28 | // this is a bug in node module loading as far as I am concerned 29 | var util = _dereq_('util/'); 30 | 31 | var pSlice = Array.prototype.slice; 32 | var hasOwn = Object.prototype.hasOwnProperty; 33 | 34 | // 1. The assert module provides functions that throw 35 | // AssertionError's when particular conditions are not met. The 36 | // assert module must conform to the following interface. 37 | 38 | var assert = module.exports = ok; 39 | 40 | // 2. The AssertionError is defined in assert. 41 | // new assert.AssertionError({ message: message, 42 | // actual: actual, 43 | // expected: expected }) 44 | 45 | assert.AssertionError = function AssertionError(options) { 46 | this.name = 'AssertionError'; 47 | this.actual = options.actual; 48 | this.expected = options.expected; 49 | this.operator = options.operator; 50 | if (options.message) { 51 | this.message = options.message; 52 | this.generatedMessage = false; 53 | } else { 54 | this.message = getMessage(this); 55 | this.generatedMessage = true; 56 | } 57 | var stackStartFunction = options.stackStartFunction || fail; 58 | 59 | if (Error.captureStackTrace) { 60 | Error.captureStackTrace(this, stackStartFunction); 61 | } 62 | else { 63 | // non v8 browsers so we can have a stacktrace 64 | var err = new Error(); 65 | if (err.stack) { 66 | var out = err.stack; 67 | 68 | // try to strip useless frames 69 | var fn_name = stackStartFunction.name; 70 | var idx = out.indexOf('\n' + fn_name); 71 | if (idx >= 0) { 72 | // once we have located the function frame 73 | // we need to strip out everything before it (and its line) 74 | var next_line = out.indexOf('\n', idx + 1); 75 | out = out.substring(next_line + 1); 76 | } 77 | 78 | this.stack = out; 79 | } 80 | } 81 | }; 82 | 83 | // assert.AssertionError instanceof Error 84 | util.inherits(assert.AssertionError, Error); 85 | 86 | function replacer(key, value) { 87 | if (util.isUndefined(value)) { 88 | return '' + value; 89 | } 90 | if (util.isNumber(value) && (isNaN(value) || !isFinite(value))) { 91 | return value.toString(); 92 | } 93 | if (util.isFunction(value) || util.isRegExp(value)) { 94 | return value.toString(); 95 | } 96 | return value; 97 | } 98 | 99 | function truncate(s, n) { 100 | if (util.isString(s)) { 101 | return s.length < n ? s : s.slice(0, n); 102 | } else { 103 | return s; 104 | } 105 | } 106 | 107 | function getMessage(self) { 108 | return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + 109 | self.operator + ' ' + 110 | truncate(JSON.stringify(self.expected, replacer), 128); 111 | } 112 | 113 | // At present only the three keys mentioned above are used and 114 | // understood by the spec. Implementations or sub modules can pass 115 | // other keys to the AssertionError's constructor - they will be 116 | // ignored. 117 | 118 | // 3. All of the following functions must throw an AssertionError 119 | // when a corresponding condition is not met, with a message that 120 | // may be undefined if not provided. All assertion methods provide 121 | // both the actual and expected values to the assertion error for 122 | // display purposes. 123 | 124 | function fail(actual, expected, message, operator, stackStartFunction) { 125 | throw new assert.AssertionError({ 126 | message: message, 127 | actual: actual, 128 | expected: expected, 129 | operator: operator, 130 | stackStartFunction: stackStartFunction 131 | }); 132 | } 133 | 134 | // EXTENSION! allows for well behaved errors defined elsewhere. 135 | assert.fail = fail; 136 | 137 | // 4. Pure assertion tests whether a value is truthy, as determined 138 | // by !!guard. 139 | // assert.ok(guard, message_opt); 140 | // This statement is equivalent to assert.equal(true, !!guard, 141 | // message_opt);. To test strictly for the value true, use 142 | // assert.strictEqual(true, guard, message_opt);. 143 | 144 | function ok(value, message) { 145 | if (!value) fail(value, true, message, '==', assert.ok); 146 | } 147 | assert.ok = ok; 148 | 149 | // 5. The equality assertion tests shallow, coercive equality with 150 | // ==. 151 | // assert.equal(actual, expected, message_opt); 152 | 153 | assert.equal = function equal(actual, expected, message) { 154 | if (actual != expected) fail(actual, expected, message, '==', assert.equal); 155 | }; 156 | 157 | // 6. The non-equality assertion tests for whether two objects are not equal 158 | // with != assert.notEqual(actual, expected, message_opt); 159 | 160 | assert.notEqual = function notEqual(actual, expected, message) { 161 | if (actual == expected) { 162 | fail(actual, expected, message, '!=', assert.notEqual); 163 | } 164 | }; 165 | 166 | // 7. The equivalence assertion tests a deep equality relation. 167 | // assert.deepEqual(actual, expected, message_opt); 168 | 169 | assert.deepEqual = function deepEqual(actual, expected, message) { 170 | if (!_deepEqual(actual, expected)) { 171 | fail(actual, expected, message, 'deepEqual', assert.deepEqual); 172 | } 173 | }; 174 | 175 | function _deepEqual(actual, expected) { 176 | // 7.1. All identical values are equivalent, as determined by ===. 177 | if (actual === expected) { 178 | return true; 179 | 180 | } else if (util.isBuffer(actual) && util.isBuffer(expected)) { 181 | if (actual.length != expected.length) return false; 182 | 183 | for (var i = 0; i < actual.length; i++) { 184 | if (actual[i] !== expected[i]) return false; 185 | } 186 | 187 | return true; 188 | 189 | // 7.2. If the expected value is a Date object, the actual value is 190 | // equivalent if it is also a Date object that refers to the same time. 191 | } else if (util.isDate(actual) && util.isDate(expected)) { 192 | return actual.getTime() === expected.getTime(); 193 | 194 | // 7.3 If the expected value is a RegExp object, the actual value is 195 | // equivalent if it is also a RegExp object with the same source and 196 | // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). 197 | } else if (util.isRegExp(actual) && util.isRegExp(expected)) { 198 | return actual.source === expected.source && 199 | actual.global === expected.global && 200 | actual.multiline === expected.multiline && 201 | actual.lastIndex === expected.lastIndex && 202 | actual.ignoreCase === expected.ignoreCase; 203 | 204 | // 7.4. Other pairs that do not both pass typeof value == 'object', 205 | // equivalence is determined by ==. 206 | } else if (!util.isObject(actual) && !util.isObject(expected)) { 207 | return actual == expected; 208 | 209 | // 7.5 For all other Object pairs, including Array objects, equivalence is 210 | // determined by having the same number of owned properties (as verified 211 | // with Object.prototype.hasOwnProperty.call), the same set of keys 212 | // (although not necessarily the same order), equivalent values for every 213 | // corresponding key, and an identical 'prototype' property. Note: this 214 | // accounts for both named and indexed properties on Arrays. 215 | } else { 216 | return objEquiv(actual, expected); 217 | } 218 | } 219 | 220 | function isArguments(object) { 221 | return Object.prototype.toString.call(object) == '[object Arguments]'; 222 | } 223 | 224 | function objEquiv(a, b) { 225 | if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) 226 | return false; 227 | // an identical 'prototype' property. 228 | if (a.prototype !== b.prototype) return false; 229 | //~~~I've managed to break Object.keys through screwy arguments passing. 230 | // Converting to array solves the problem. 231 | if (isArguments(a)) { 232 | if (!isArguments(b)) { 233 | return false; 234 | } 235 | a = pSlice.call(a); 236 | b = pSlice.call(b); 237 | return _deepEqual(a, b); 238 | } 239 | try { 240 | var ka = objectKeys(a), 241 | kb = objectKeys(b), 242 | key, i; 243 | } catch (e) {//happens when one is a string literal and the other isn't 244 | return false; 245 | } 246 | // having the same number of owned properties (keys incorporates 247 | // hasOwnProperty) 248 | if (ka.length != kb.length) 249 | return false; 250 | //the same set of keys (although not necessarily the same order), 251 | ka.sort(); 252 | kb.sort(); 253 | //~~~cheap key test 254 | for (i = ka.length - 1; i >= 0; i--) { 255 | if (ka[i] != kb[i]) 256 | return false; 257 | } 258 | //equivalent values for every corresponding key, and 259 | //~~~possibly expensive deep test 260 | for (i = ka.length - 1; i >= 0; i--) { 261 | key = ka[i]; 262 | if (!_deepEqual(a[key], b[key])) return false; 263 | } 264 | return true; 265 | } 266 | 267 | // 8. The non-equivalence assertion tests for any deep inequality. 268 | // assert.notDeepEqual(actual, expected, message_opt); 269 | 270 | assert.notDeepEqual = function notDeepEqual(actual, expected, message) { 271 | if (_deepEqual(actual, expected)) { 272 | fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); 273 | } 274 | }; 275 | 276 | // 9. The strict equality assertion tests strict equality, as determined by ===. 277 | // assert.strictEqual(actual, expected, message_opt); 278 | 279 | assert.strictEqual = function strictEqual(actual, expected, message) { 280 | if (actual !== expected) { 281 | fail(actual, expected, message, '===', assert.strictEqual); 282 | } 283 | }; 284 | 285 | // 10. The strict non-equality assertion tests for strict inequality, as 286 | // determined by !==. assert.notStrictEqual(actual, expected, message_opt); 287 | 288 | assert.notStrictEqual = function notStrictEqual(actual, expected, message) { 289 | if (actual === expected) { 290 | fail(actual, expected, message, '!==', assert.notStrictEqual); 291 | } 292 | }; 293 | 294 | function expectedException(actual, expected) { 295 | if (!actual || !expected) { 296 | return false; 297 | } 298 | 299 | if (Object.prototype.toString.call(expected) == '[object RegExp]') { 300 | return expected.test(actual); 301 | } else if (actual instanceof expected) { 302 | return true; 303 | } else if (expected.call({}, actual) === true) { 304 | return true; 305 | } 306 | 307 | return false; 308 | } 309 | 310 | function _throws(shouldThrow, block, expected, message) { 311 | var actual; 312 | 313 | if (util.isString(expected)) { 314 | message = expected; 315 | expected = null; 316 | } 317 | 318 | try { 319 | block(); 320 | } catch (e) { 321 | actual = e; 322 | } 323 | 324 | message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + 325 | (message ? ' ' + message : '.'); 326 | 327 | if (shouldThrow && !actual) { 328 | fail(actual, expected, 'Missing expected exception' + message); 329 | } 330 | 331 | if (!shouldThrow && expectedException(actual, expected)) { 332 | fail(actual, expected, 'Got unwanted exception' + message); 333 | } 334 | 335 | if ((shouldThrow && actual && expected && 336 | !expectedException(actual, expected)) || (!shouldThrow && actual)) { 337 | throw actual; 338 | } 339 | } 340 | 341 | // 11. Expected to throw an error: 342 | // assert.throws(block, Error_opt, message_opt); 343 | 344 | assert.throws = function(block, /*optional*/error, /*optional*/message) { 345 | _throws.apply(this, [true].concat(pSlice.call(arguments))); 346 | }; 347 | 348 | // EXTENSION! This is annoying to write outside this module. 349 | assert.doesNotThrow = function(block, /*optional*/message) { 350 | _throws.apply(this, [false].concat(pSlice.call(arguments))); 351 | }; 352 | 353 | assert.ifError = function(err) { if (err) {throw err;}}; 354 | 355 | var objectKeys = Object.keys || function (obj) { 356 | var keys = []; 357 | for (var key in obj) { 358 | if (hasOwn.call(obj, key)) keys.push(key); 359 | } 360 | return keys; 361 | }; 362 | 363 | },{"util/":5}],2:[function(_dereq_,module,exports){ 364 | if (typeof Object.create === 'function') { 365 | // implementation from standard node.js 'util' module 366 | module.exports = function inherits(ctor, superCtor) { 367 | ctor.super_ = superCtor 368 | ctor.prototype = Object.create(superCtor.prototype, { 369 | constructor: { 370 | value: ctor, 371 | enumerable: false, 372 | writable: true, 373 | configurable: true 374 | } 375 | }); 376 | }; 377 | } else { 378 | // old school shim for old browsers 379 | module.exports = function inherits(ctor, superCtor) { 380 | ctor.super_ = superCtor 381 | var TempCtor = function () {} 382 | TempCtor.prototype = superCtor.prototype 383 | ctor.prototype = new TempCtor() 384 | ctor.prototype.constructor = ctor 385 | } 386 | } 387 | 388 | },{}],3:[function(_dereq_,module,exports){ 389 | // shim for using process in browser 390 | 391 | var process = module.exports = {}; 392 | 393 | process.nextTick = (function () { 394 | var canSetImmediate = typeof window !== 'undefined' 395 | && window.setImmediate; 396 | var canPost = typeof window !== 'undefined' 397 | && window.postMessage && window.addEventListener 398 | ; 399 | 400 | if (canSetImmediate) { 401 | return function (f) { return window.setImmediate(f) }; 402 | } 403 | 404 | if (canPost) { 405 | var queue = []; 406 | window.addEventListener('message', function (ev) { 407 | var source = ev.source; 408 | if ((source === window || source === null) && ev.data === 'process-tick') { 409 | ev.stopPropagation(); 410 | if (queue.length > 0) { 411 | var fn = queue.shift(); 412 | fn(); 413 | } 414 | } 415 | }, true); 416 | 417 | return function nextTick(fn) { 418 | queue.push(fn); 419 | window.postMessage('process-tick', '*'); 420 | }; 421 | } 422 | 423 | return function nextTick(fn) { 424 | setTimeout(fn, 0); 425 | }; 426 | })(); 427 | 428 | process.title = 'browser'; 429 | process.browser = true; 430 | process.env = {}; 431 | process.argv = []; 432 | 433 | process.binding = function (name) { 434 | throw new Error('process.binding is not supported'); 435 | } 436 | 437 | // TODO(shtylman) 438 | process.cwd = function () { return '/' }; 439 | process.chdir = function (dir) { 440 | throw new Error('process.chdir is not supported'); 441 | }; 442 | 443 | },{}],4:[function(_dereq_,module,exports){ 444 | module.exports = function isBuffer(arg) { 445 | return arg && typeof arg === 'object' 446 | && typeof arg.copy === 'function' 447 | && typeof arg.fill === 'function' 448 | && typeof arg.readUInt8 === 'function'; 449 | } 450 | },{}],5:[function(_dereq_,module,exports){ 451 | (function (process,global){// Copyright Joyent, Inc. and other Node contributors. 452 | // 453 | // Permission is hereby granted, free of charge, to any person obtaining a 454 | // copy of this software and associated documentation files (the 455 | // "Software"), to deal in the Software without restriction, including 456 | // without limitation the rights to use, copy, modify, merge, publish, 457 | // distribute, sublicense, and/or sell copies of the Software, and to permit 458 | // persons to whom the Software is furnished to do so, subject to the 459 | // following conditions: 460 | // 461 | // The above copyright notice and this permission notice shall be included 462 | // in all copies or substantial portions of the Software. 463 | // 464 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 465 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 466 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 467 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 468 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 469 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 470 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 471 | 472 | var formatRegExp = /%[sdj%]/g; 473 | exports.format = function(f) { 474 | if (!isString(f)) { 475 | var objects = []; 476 | for (var i = 0; i < arguments.length; i++) { 477 | objects.push(inspect(arguments[i])); 478 | } 479 | return objects.join(' '); 480 | } 481 | 482 | var i = 1; 483 | var args = arguments; 484 | var len = args.length; 485 | var str = String(f).replace(formatRegExp, function(x) { 486 | if (x === '%%') return '%'; 487 | if (i >= len) return x; 488 | switch (x) { 489 | case '%s': return String(args[i++]); 490 | case '%d': return Number(args[i++]); 491 | case '%j': 492 | try { 493 | return JSON.stringify(args[i++]); 494 | } catch (_) { 495 | return '[Circular]'; 496 | } 497 | default: 498 | return x; 499 | } 500 | }); 501 | for (var x = args[i]; i < len; x = args[++i]) { 502 | if (isNull(x) || !isObject(x)) { 503 | str += ' ' + x; 504 | } else { 505 | str += ' ' + inspect(x); 506 | } 507 | } 508 | return str; 509 | }; 510 | 511 | 512 | // Mark that a method should not be used. 513 | // Returns a modified function which warns once by default. 514 | // If --no-deprecation is set, then it is a no-op. 515 | exports.deprecate = function(fn, msg) { 516 | // Allow for deprecating things in the process of starting up. 517 | if (isUndefined(global.process)) { 518 | return function() { 519 | return exports.deprecate(fn, msg).apply(this, arguments); 520 | }; 521 | } 522 | 523 | if (process.noDeprecation === true) { 524 | return fn; 525 | } 526 | 527 | var warned = false; 528 | function deprecated() { 529 | if (!warned) { 530 | if (process.throwDeprecation) { 531 | throw new Error(msg); 532 | } else if (process.traceDeprecation) { 533 | console.trace(msg); 534 | } else { 535 | console.error(msg); 536 | } 537 | warned = true; 538 | } 539 | return fn.apply(this, arguments); 540 | } 541 | 542 | return deprecated; 543 | }; 544 | 545 | 546 | var debugs = {}; 547 | var debugEnviron; 548 | exports.debuglog = function(set) { 549 | if (isUndefined(debugEnviron)) 550 | debugEnviron = process.env.NODE_DEBUG || ''; 551 | set = set.toUpperCase(); 552 | if (!debugs[set]) { 553 | if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { 554 | var pid = process.pid; 555 | debugs[set] = function() { 556 | var msg = exports.format.apply(exports, arguments); 557 | console.error('%s %d: %s', set, pid, msg); 558 | }; 559 | } else { 560 | debugs[set] = function() {}; 561 | } 562 | } 563 | return debugs[set]; 564 | }; 565 | 566 | 567 | /** 568 | * Echos the value of a value. Trys to print the value out 569 | * in the best way possible given the different types. 570 | * 571 | * @param {Object} obj The object to print out. 572 | * @param {Object} opts Optional options object that alters the output. 573 | */ 574 | /* legacy: obj, showHidden, depth, colors*/ 575 | function inspect(obj, opts) { 576 | // default options 577 | var ctx = { 578 | seen: [], 579 | stylize: stylizeNoColor 580 | }; 581 | // legacy... 582 | if (arguments.length >= 3) ctx.depth = arguments[2]; 583 | if (arguments.length >= 4) ctx.colors = arguments[3]; 584 | if (isBoolean(opts)) { 585 | // legacy... 586 | ctx.showHidden = opts; 587 | } else if (opts) { 588 | // got an "options" object 589 | exports._extend(ctx, opts); 590 | } 591 | // set default options 592 | if (isUndefined(ctx.showHidden)) ctx.showHidden = false; 593 | if (isUndefined(ctx.depth)) ctx.depth = 2; 594 | if (isUndefined(ctx.colors)) ctx.colors = false; 595 | if (isUndefined(ctx.customInspect)) ctx.customInspect = true; 596 | if (ctx.colors) ctx.stylize = stylizeWithColor; 597 | return formatValue(ctx, obj, ctx.depth); 598 | } 599 | exports.inspect = inspect; 600 | 601 | 602 | // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics 603 | inspect.colors = { 604 | 'bold' : [1, 22], 605 | 'italic' : [3, 23], 606 | 'underline' : [4, 24], 607 | 'inverse' : [7, 27], 608 | 'white' : [37, 39], 609 | 'grey' : [90, 39], 610 | 'black' : [30, 39], 611 | 'blue' : [34, 39], 612 | 'cyan' : [36, 39], 613 | 'green' : [32, 39], 614 | 'magenta' : [35, 39], 615 | 'red' : [31, 39], 616 | 'yellow' : [33, 39] 617 | }; 618 | 619 | // Don't use 'blue' not visible on cmd.exe 620 | inspect.styles = { 621 | 'special': 'cyan', 622 | 'number': 'yellow', 623 | 'boolean': 'yellow', 624 | 'undefined': 'grey', 625 | 'null': 'bold', 626 | 'string': 'green', 627 | 'date': 'magenta', 628 | // "name": intentionally not styling 629 | 'regexp': 'red' 630 | }; 631 | 632 | 633 | function stylizeWithColor(str, styleType) { 634 | var style = inspect.styles[styleType]; 635 | 636 | if (style) { 637 | return '\u001b[' + inspect.colors[style][0] + 'm' + str + 638 | '\u001b[' + inspect.colors[style][1] + 'm'; 639 | } else { 640 | return str; 641 | } 642 | } 643 | 644 | 645 | function stylizeNoColor(str, styleType) { 646 | return str; 647 | } 648 | 649 | 650 | function arrayToHash(array) { 651 | var hash = {}; 652 | 653 | array.forEach(function(val, idx) { 654 | hash[val] = true; 655 | }); 656 | 657 | return hash; 658 | } 659 | 660 | 661 | function formatValue(ctx, value, recurseTimes) { 662 | // Provide a hook for user-specified inspect functions. 663 | // Check that value is an object with an inspect function on it 664 | if (ctx.customInspect && 665 | value && 666 | isFunction(value.inspect) && 667 | // Filter out the util module, it's inspect function is special 668 | value.inspect !== exports.inspect && 669 | // Also filter out any prototype objects using the circular check. 670 | !(value.constructor && value.constructor.prototype === value)) { 671 | var ret = value.inspect(recurseTimes, ctx); 672 | if (!isString(ret)) { 673 | ret = formatValue(ctx, ret, recurseTimes); 674 | } 675 | return ret; 676 | } 677 | 678 | // Primitive types cannot have properties 679 | var primitive = formatPrimitive(ctx, value); 680 | if (primitive) { 681 | return primitive; 682 | } 683 | 684 | // Look up the keys of the object. 685 | var keys = Object.keys(value); 686 | var visibleKeys = arrayToHash(keys); 687 | 688 | if (ctx.showHidden) { 689 | keys = Object.getOwnPropertyNames(value); 690 | } 691 | 692 | // IE doesn't make error fields non-enumerable 693 | // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx 694 | if (isError(value) 695 | && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { 696 | return formatError(value); 697 | } 698 | 699 | // Some type of object without properties can be shortcutted. 700 | if (keys.length === 0) { 701 | if (isFunction(value)) { 702 | var name = value.name ? ': ' + value.name : ''; 703 | return ctx.stylize('[Function' + name + ']', 'special'); 704 | } 705 | if (isRegExp(value)) { 706 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 707 | } 708 | if (isDate(value)) { 709 | return ctx.stylize(Date.prototype.toString.call(value), 'date'); 710 | } 711 | if (isError(value)) { 712 | return formatError(value); 713 | } 714 | } 715 | 716 | var base = '', array = false, braces = ['{', '}']; 717 | 718 | // Make Array say that they are Array 719 | if (isArray(value)) { 720 | array = true; 721 | braces = ['[', ']']; 722 | } 723 | 724 | // Make functions say that they are functions 725 | if (isFunction(value)) { 726 | var n = value.name ? ': ' + value.name : ''; 727 | base = ' [Function' + n + ']'; 728 | } 729 | 730 | // Make RegExps say that they are RegExps 731 | if (isRegExp(value)) { 732 | base = ' ' + RegExp.prototype.toString.call(value); 733 | } 734 | 735 | // Make dates with properties first say the date 736 | if (isDate(value)) { 737 | base = ' ' + Date.prototype.toUTCString.call(value); 738 | } 739 | 740 | // Make error with message first say the error 741 | if (isError(value)) { 742 | base = ' ' + formatError(value); 743 | } 744 | 745 | if (keys.length === 0 && (!array || value.length == 0)) { 746 | return braces[0] + base + braces[1]; 747 | } 748 | 749 | if (recurseTimes < 0) { 750 | if (isRegExp(value)) { 751 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 752 | } else { 753 | return ctx.stylize('[Object]', 'special'); 754 | } 755 | } 756 | 757 | ctx.seen.push(value); 758 | 759 | var output; 760 | if (array) { 761 | output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); 762 | } else { 763 | output = keys.map(function(key) { 764 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); 765 | }); 766 | } 767 | 768 | ctx.seen.pop(); 769 | 770 | return reduceToSingleString(output, base, braces); 771 | } 772 | 773 | 774 | function formatPrimitive(ctx, value) { 775 | if (isUndefined(value)) 776 | return ctx.stylize('undefined', 'undefined'); 777 | if (isString(value)) { 778 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') 779 | .replace(/'/g, "\\'") 780 | .replace(/\\"/g, '"') + '\''; 781 | return ctx.stylize(simple, 'string'); 782 | } 783 | if (isNumber(value)) 784 | return ctx.stylize('' + value, 'number'); 785 | if (isBoolean(value)) 786 | return ctx.stylize('' + value, 'boolean'); 787 | // For some reason typeof null is "object", so special case here. 788 | if (isNull(value)) 789 | return ctx.stylize('null', 'null'); 790 | } 791 | 792 | 793 | function formatError(value) { 794 | return '[' + Error.prototype.toString.call(value) + ']'; 795 | } 796 | 797 | 798 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { 799 | var output = []; 800 | for (var i = 0, l = value.length; i < l; ++i) { 801 | if (hasOwnProperty(value, String(i))) { 802 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 803 | String(i), true)); 804 | } else { 805 | output.push(''); 806 | } 807 | } 808 | keys.forEach(function(key) { 809 | if (!key.match(/^\d+$/)) { 810 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 811 | key, true)); 812 | } 813 | }); 814 | return output; 815 | } 816 | 817 | 818 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { 819 | var name, str, desc; 820 | desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; 821 | if (desc.get) { 822 | if (desc.set) { 823 | str = ctx.stylize('[Getter/Setter]', 'special'); 824 | } else { 825 | str = ctx.stylize('[Getter]', 'special'); 826 | } 827 | } else { 828 | if (desc.set) { 829 | str = ctx.stylize('[Setter]', 'special'); 830 | } 831 | } 832 | if (!hasOwnProperty(visibleKeys, key)) { 833 | name = '[' + key + ']'; 834 | } 835 | if (!str) { 836 | if (ctx.seen.indexOf(desc.value) < 0) { 837 | if (isNull(recurseTimes)) { 838 | str = formatValue(ctx, desc.value, null); 839 | } else { 840 | str = formatValue(ctx, desc.value, recurseTimes - 1); 841 | } 842 | if (str.indexOf('\n') > -1) { 843 | if (array) { 844 | str = str.split('\n').map(function(line) { 845 | return ' ' + line; 846 | }).join('\n').substr(2); 847 | } else { 848 | str = '\n' + str.split('\n').map(function(line) { 849 | return ' ' + line; 850 | }).join('\n'); 851 | } 852 | } 853 | } else { 854 | str = ctx.stylize('[Circular]', 'special'); 855 | } 856 | } 857 | if (isUndefined(name)) { 858 | if (array && key.match(/^\d+$/)) { 859 | return str; 860 | } 861 | name = JSON.stringify('' + key); 862 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { 863 | name = name.substr(1, name.length - 2); 864 | name = ctx.stylize(name, 'name'); 865 | } else { 866 | name = name.replace(/'/g, "\\'") 867 | .replace(/\\"/g, '"') 868 | .replace(/(^"|"$)/g, "'"); 869 | name = ctx.stylize(name, 'string'); 870 | } 871 | } 872 | 873 | return name + ': ' + str; 874 | } 875 | 876 | 877 | function reduceToSingleString(output, base, braces) { 878 | var numLinesEst = 0; 879 | var length = output.reduce(function(prev, cur) { 880 | numLinesEst++; 881 | if (cur.indexOf('\n') >= 0) numLinesEst++; 882 | return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; 883 | }, 0); 884 | 885 | if (length > 60) { 886 | return braces[0] + 887 | (base === '' ? '' : base + '\n ') + 888 | ' ' + 889 | output.join(',\n ') + 890 | ' ' + 891 | braces[1]; 892 | } 893 | 894 | return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; 895 | } 896 | 897 | 898 | // NOTE: These type checking functions intentionally don't use `instanceof` 899 | // because it is fragile and can be easily faked with `Object.create()`. 900 | function isArray(ar) { 901 | return Array.isArray(ar); 902 | } 903 | exports.isArray = isArray; 904 | 905 | function isBoolean(arg) { 906 | return typeof arg === 'boolean'; 907 | } 908 | exports.isBoolean = isBoolean; 909 | 910 | function isNull(arg) { 911 | return arg === null; 912 | } 913 | exports.isNull = isNull; 914 | 915 | function isNullOrUndefined(arg) { 916 | return arg == null; 917 | } 918 | exports.isNullOrUndefined = isNullOrUndefined; 919 | 920 | function isNumber(arg) { 921 | return typeof arg === 'number'; 922 | } 923 | exports.isNumber = isNumber; 924 | 925 | function isString(arg) { 926 | return typeof arg === 'string'; 927 | } 928 | exports.isString = isString; 929 | 930 | function isSymbol(arg) { 931 | return typeof arg === 'symbol'; 932 | } 933 | exports.isSymbol = isSymbol; 934 | 935 | function isUndefined(arg) { 936 | return arg === void 0; 937 | } 938 | exports.isUndefined = isUndefined; 939 | 940 | function isRegExp(re) { 941 | return isObject(re) && objectToString(re) === '[object RegExp]'; 942 | } 943 | exports.isRegExp = isRegExp; 944 | 945 | function isObject(arg) { 946 | return typeof arg === 'object' && arg !== null; 947 | } 948 | exports.isObject = isObject; 949 | 950 | function isDate(d) { 951 | return isObject(d) && objectToString(d) === '[object Date]'; 952 | } 953 | exports.isDate = isDate; 954 | 955 | function isError(e) { 956 | return isObject(e) && 957 | (objectToString(e) === '[object Error]' || e instanceof Error); 958 | } 959 | exports.isError = isError; 960 | 961 | function isFunction(arg) { 962 | return typeof arg === 'function'; 963 | } 964 | exports.isFunction = isFunction; 965 | 966 | function isPrimitive(arg) { 967 | return arg === null || 968 | typeof arg === 'boolean' || 969 | typeof arg === 'number' || 970 | typeof arg === 'string' || 971 | typeof arg === 'symbol' || // ES6 symbol 972 | typeof arg === 'undefined'; 973 | } 974 | exports.isPrimitive = isPrimitive; 975 | 976 | exports.isBuffer = _dereq_('./support/isBuffer'); 977 | 978 | function objectToString(o) { 979 | return Object.prototype.toString.call(o); 980 | } 981 | 982 | 983 | function pad(n) { 984 | return n < 10 ? '0' + n.toString(10) : n.toString(10); 985 | } 986 | 987 | 988 | var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 989 | 'Oct', 'Nov', 'Dec']; 990 | 991 | // 26 Feb 16:19:34 992 | function timestamp() { 993 | var d = new Date(); 994 | var time = [pad(d.getHours()), 995 | pad(d.getMinutes()), 996 | pad(d.getSeconds())].join(':'); 997 | return [d.getDate(), months[d.getMonth()], time].join(' '); 998 | } 999 | 1000 | 1001 | // log is just a thin wrapper to console.log that prepends a timestamp 1002 | exports.log = function() { 1003 | console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); 1004 | }; 1005 | 1006 | 1007 | /** 1008 | * Inherit the prototype methods from one constructor into another. 1009 | * 1010 | * The Function.prototype.inherits from lang.js rewritten as a standalone 1011 | * function (not on Function.prototype). NOTE: If this file is to be loaded 1012 | * during bootstrapping this function needs to be rewritten using some native 1013 | * functions as prototype setup using normal JavaScript does not work as 1014 | * expected during bootstrapping (see mirror.js in r114903). 1015 | * 1016 | * @param {function} ctor Constructor function which needs to inherit the 1017 | * prototype. 1018 | * @param {function} superCtor Constructor function to inherit prototype from. 1019 | */ 1020 | exports.inherits = _dereq_('inherits'); 1021 | 1022 | exports._extend = function(origin, add) { 1023 | // Don't do anything if add isn't an object 1024 | if (!add || !isObject(add)) return origin; 1025 | 1026 | var keys = Object.keys(add); 1027 | var i = keys.length; 1028 | while (i--) { 1029 | origin[keys[i]] = add[keys[i]]; 1030 | } 1031 | return origin; 1032 | }; 1033 | 1034 | function hasOwnProperty(obj, prop) { 1035 | return Object.prototype.hasOwnProperty.call(obj, prop); 1036 | } 1037 | }).call(this,_dereq_("/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 1038 | },{"./support/isBuffer":4,"/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":3,"inherits":2}],6:[function(_dereq_,module,exports){ 1039 | 'use strict'; 1040 | var assert = _dereq_('assert'); 1041 | 1042 | module.exports = function() { 1043 | 1044 | var listItem; 1045 | 1046 | this.World = _dereq_('../support/world').World; 1047 | 1048 | this.Given(/^I have an empty grocery list$/, function(callback) { 1049 | this.groceryListApplication.list.empty(); 1050 | callback(); 1051 | }); 1052 | 1053 | this.When(/^I add an item to the list$/, function(callback) { 1054 | listItem = this.createGroceryItem(); 1055 | this.groceryListApplication.list.add(listItem); 1056 | callback(); 1057 | }); 1058 | 1059 | this.Then(/^The grocery list contains a single item$/, function(callback) { 1060 | assert.equal(this.groceryListApplication.list.getAll().length, 1, 'Grocery List should grow by one item.'); 1061 | callback(); 1062 | }); 1063 | 1064 | this.Then(/^I can access that item from the grocery list$/, function(callback) { 1065 | assert.notEqual(this.groceryListApplication.list.getItemIndex(listItem), -1, 'Added item should be found at non-negative index.'); 1066 | callback(); 1067 | }); 1068 | 1069 | }; 1070 | },{"../support/world":7,"assert":1}],7:[function(_dereq_,module,exports){ 1071 | (function (process){/*global window, document*/ 1072 | 'use strict'; 1073 | 1074 | var World = function World(callback) { 1075 | 1076 | this.window = process.browser ? window : {}; 1077 | this.app = undefined; 1078 | this.groceryListApplication = undefined; 1079 | 1080 | var defineGlobals = function(w, doc) { 1081 | this.app = w.app; 1082 | }; 1083 | 1084 | this.domload = function(callback) { 1085 | (function(world) { 1086 | if(document.readyState === 'complete') { 1087 | defineGlobals.call(world, window, document); 1088 | callback(); 1089 | } 1090 | else { 1091 | var delegate = document.addEventListener ? 'addEventListener' : 'attachEvent'; 1092 | var eventType = document.addEventListener ? 'load' : 'onload'; 1093 | window[delegate](eventType, function() { 1094 | defineGlobals.call(world, window, document); 1095 | callback(); 1096 | }); 1097 | } 1098 | }(this)); 1099 | }; 1100 | 1101 | this.openGroceryList = function() { 1102 | return this.app.newSession(); 1103 | }; 1104 | this.createGroceryItem = function() { 1105 | return 'apple'; 1106 | }; 1107 | 1108 | this.getGroceryListView = function() { 1109 | return this.groceryListApplication.$listview; 1110 | }; 1111 | 1112 | this.getGroceryListViewItemAtIndex = function(index) { 1113 | return this.groceryListApplication.$listview.childNodes[index].textContent; 1114 | } 1115 | 1116 | this.emptyGroceryListView = function() { 1117 | this.groceryListApplication.empty(); 1118 | }; 1119 | 1120 | this.enterNewGorceryListItem = function(item) { 1121 | this.groceryListApplication.enterNewItem(item); 1122 | }; 1123 | 1124 | this.createClickEvent = function() { 1125 | var event = document.createEvent('MouseEvents'); 1126 | event.initEvent('click', true, false); 1127 | return event; 1128 | }; 1129 | 1130 | this.clickAddGroceryListItem = function() { 1131 | var clickevent = this.createClickEvent(); 1132 | this.groceryListApplication.$addbutton.dispatchEvent(clickevent); 1133 | }; 1134 | 1135 | callback(); 1136 | 1137 | }; 1138 | 1139 | module.exports.World = World;}).call(this,_dereq_("/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) 1140 | },{"/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":3}]},{},[6]) 1141 | (6) 1142 | }); -------------------------------------------------------------------------------- /test/addItemViewSteps.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.addItemViewSteps=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the 'Software'), to 11 | // deal in the Software without restriction, including without limitation the 12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 13 | // sell copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | // when used in node, this will actually load the util module we depend on 27 | // versus loading the builtin util module as happens otherwise 28 | // this is a bug in node module loading as far as I am concerned 29 | var util = _dereq_('util/'); 30 | 31 | var pSlice = Array.prototype.slice; 32 | var hasOwn = Object.prototype.hasOwnProperty; 33 | 34 | // 1. The assert module provides functions that throw 35 | // AssertionError's when particular conditions are not met. The 36 | // assert module must conform to the following interface. 37 | 38 | var assert = module.exports = ok; 39 | 40 | // 2. The AssertionError is defined in assert. 41 | // new assert.AssertionError({ message: message, 42 | // actual: actual, 43 | // expected: expected }) 44 | 45 | assert.AssertionError = function AssertionError(options) { 46 | this.name = 'AssertionError'; 47 | this.actual = options.actual; 48 | this.expected = options.expected; 49 | this.operator = options.operator; 50 | if (options.message) { 51 | this.message = options.message; 52 | this.generatedMessage = false; 53 | } else { 54 | this.message = getMessage(this); 55 | this.generatedMessage = true; 56 | } 57 | var stackStartFunction = options.stackStartFunction || fail; 58 | 59 | if (Error.captureStackTrace) { 60 | Error.captureStackTrace(this, stackStartFunction); 61 | } 62 | else { 63 | // non v8 browsers so we can have a stacktrace 64 | var err = new Error(); 65 | if (err.stack) { 66 | var out = err.stack; 67 | 68 | // try to strip useless frames 69 | var fn_name = stackStartFunction.name; 70 | var idx = out.indexOf('\n' + fn_name); 71 | if (idx >= 0) { 72 | // once we have located the function frame 73 | // we need to strip out everything before it (and its line) 74 | var next_line = out.indexOf('\n', idx + 1); 75 | out = out.substring(next_line + 1); 76 | } 77 | 78 | this.stack = out; 79 | } 80 | } 81 | }; 82 | 83 | // assert.AssertionError instanceof Error 84 | util.inherits(assert.AssertionError, Error); 85 | 86 | function replacer(key, value) { 87 | if (util.isUndefined(value)) { 88 | return '' + value; 89 | } 90 | if (util.isNumber(value) && (isNaN(value) || !isFinite(value))) { 91 | return value.toString(); 92 | } 93 | if (util.isFunction(value) || util.isRegExp(value)) { 94 | return value.toString(); 95 | } 96 | return value; 97 | } 98 | 99 | function truncate(s, n) { 100 | if (util.isString(s)) { 101 | return s.length < n ? s : s.slice(0, n); 102 | } else { 103 | return s; 104 | } 105 | } 106 | 107 | function getMessage(self) { 108 | return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + 109 | self.operator + ' ' + 110 | truncate(JSON.stringify(self.expected, replacer), 128); 111 | } 112 | 113 | // At present only the three keys mentioned above are used and 114 | // understood by the spec. Implementations or sub modules can pass 115 | // other keys to the AssertionError's constructor - they will be 116 | // ignored. 117 | 118 | // 3. All of the following functions must throw an AssertionError 119 | // when a corresponding condition is not met, with a message that 120 | // may be undefined if not provided. All assertion methods provide 121 | // both the actual and expected values to the assertion error for 122 | // display purposes. 123 | 124 | function fail(actual, expected, message, operator, stackStartFunction) { 125 | throw new assert.AssertionError({ 126 | message: message, 127 | actual: actual, 128 | expected: expected, 129 | operator: operator, 130 | stackStartFunction: stackStartFunction 131 | }); 132 | } 133 | 134 | // EXTENSION! allows for well behaved errors defined elsewhere. 135 | assert.fail = fail; 136 | 137 | // 4. Pure assertion tests whether a value is truthy, as determined 138 | // by !!guard. 139 | // assert.ok(guard, message_opt); 140 | // This statement is equivalent to assert.equal(true, !!guard, 141 | // message_opt);. To test strictly for the value true, use 142 | // assert.strictEqual(true, guard, message_opt);. 143 | 144 | function ok(value, message) { 145 | if (!value) fail(value, true, message, '==', assert.ok); 146 | } 147 | assert.ok = ok; 148 | 149 | // 5. The equality assertion tests shallow, coercive equality with 150 | // ==. 151 | // assert.equal(actual, expected, message_opt); 152 | 153 | assert.equal = function equal(actual, expected, message) { 154 | if (actual != expected) fail(actual, expected, message, '==', assert.equal); 155 | }; 156 | 157 | // 6. The non-equality assertion tests for whether two objects are not equal 158 | // with != assert.notEqual(actual, expected, message_opt); 159 | 160 | assert.notEqual = function notEqual(actual, expected, message) { 161 | if (actual == expected) { 162 | fail(actual, expected, message, '!=', assert.notEqual); 163 | } 164 | }; 165 | 166 | // 7. The equivalence assertion tests a deep equality relation. 167 | // assert.deepEqual(actual, expected, message_opt); 168 | 169 | assert.deepEqual = function deepEqual(actual, expected, message) { 170 | if (!_deepEqual(actual, expected)) { 171 | fail(actual, expected, message, 'deepEqual', assert.deepEqual); 172 | } 173 | }; 174 | 175 | function _deepEqual(actual, expected) { 176 | // 7.1. All identical values are equivalent, as determined by ===. 177 | if (actual === expected) { 178 | return true; 179 | 180 | } else if (util.isBuffer(actual) && util.isBuffer(expected)) { 181 | if (actual.length != expected.length) return false; 182 | 183 | for (var i = 0; i < actual.length; i++) { 184 | if (actual[i] !== expected[i]) return false; 185 | } 186 | 187 | return true; 188 | 189 | // 7.2. If the expected value is a Date object, the actual value is 190 | // equivalent if it is also a Date object that refers to the same time. 191 | } else if (util.isDate(actual) && util.isDate(expected)) { 192 | return actual.getTime() === expected.getTime(); 193 | 194 | // 7.3 If the expected value is a RegExp object, the actual value is 195 | // equivalent if it is also a RegExp object with the same source and 196 | // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). 197 | } else if (util.isRegExp(actual) && util.isRegExp(expected)) { 198 | return actual.source === expected.source && 199 | actual.global === expected.global && 200 | actual.multiline === expected.multiline && 201 | actual.lastIndex === expected.lastIndex && 202 | actual.ignoreCase === expected.ignoreCase; 203 | 204 | // 7.4. Other pairs that do not both pass typeof value == 'object', 205 | // equivalence is determined by ==. 206 | } else if (!util.isObject(actual) && !util.isObject(expected)) { 207 | return actual == expected; 208 | 209 | // 7.5 For all other Object pairs, including Array objects, equivalence is 210 | // determined by having the same number of owned properties (as verified 211 | // with Object.prototype.hasOwnProperty.call), the same set of keys 212 | // (although not necessarily the same order), equivalent values for every 213 | // corresponding key, and an identical 'prototype' property. Note: this 214 | // accounts for both named and indexed properties on Arrays. 215 | } else { 216 | return objEquiv(actual, expected); 217 | } 218 | } 219 | 220 | function isArguments(object) { 221 | return Object.prototype.toString.call(object) == '[object Arguments]'; 222 | } 223 | 224 | function objEquiv(a, b) { 225 | if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) 226 | return false; 227 | // an identical 'prototype' property. 228 | if (a.prototype !== b.prototype) return false; 229 | //~~~I've managed to break Object.keys through screwy arguments passing. 230 | // Converting to array solves the problem. 231 | if (isArguments(a)) { 232 | if (!isArguments(b)) { 233 | return false; 234 | } 235 | a = pSlice.call(a); 236 | b = pSlice.call(b); 237 | return _deepEqual(a, b); 238 | } 239 | try { 240 | var ka = objectKeys(a), 241 | kb = objectKeys(b), 242 | key, i; 243 | } catch (e) {//happens when one is a string literal and the other isn't 244 | return false; 245 | } 246 | // having the same number of owned properties (keys incorporates 247 | // hasOwnProperty) 248 | if (ka.length != kb.length) 249 | return false; 250 | //the same set of keys (although not necessarily the same order), 251 | ka.sort(); 252 | kb.sort(); 253 | //~~~cheap key test 254 | for (i = ka.length - 1; i >= 0; i--) { 255 | if (ka[i] != kb[i]) 256 | return false; 257 | } 258 | //equivalent values for every corresponding key, and 259 | //~~~possibly expensive deep test 260 | for (i = ka.length - 1; i >= 0; i--) { 261 | key = ka[i]; 262 | if (!_deepEqual(a[key], b[key])) return false; 263 | } 264 | return true; 265 | } 266 | 267 | // 8. The non-equivalence assertion tests for any deep inequality. 268 | // assert.notDeepEqual(actual, expected, message_opt); 269 | 270 | assert.notDeepEqual = function notDeepEqual(actual, expected, message) { 271 | if (_deepEqual(actual, expected)) { 272 | fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); 273 | } 274 | }; 275 | 276 | // 9. The strict equality assertion tests strict equality, as determined by ===. 277 | // assert.strictEqual(actual, expected, message_opt); 278 | 279 | assert.strictEqual = function strictEqual(actual, expected, message) { 280 | if (actual !== expected) { 281 | fail(actual, expected, message, '===', assert.strictEqual); 282 | } 283 | }; 284 | 285 | // 10. The strict non-equality assertion tests for strict inequality, as 286 | // determined by !==. assert.notStrictEqual(actual, expected, message_opt); 287 | 288 | assert.notStrictEqual = function notStrictEqual(actual, expected, message) { 289 | if (actual === expected) { 290 | fail(actual, expected, message, '!==', assert.notStrictEqual); 291 | } 292 | }; 293 | 294 | function expectedException(actual, expected) { 295 | if (!actual || !expected) { 296 | return false; 297 | } 298 | 299 | if (Object.prototype.toString.call(expected) == '[object RegExp]') { 300 | return expected.test(actual); 301 | } else if (actual instanceof expected) { 302 | return true; 303 | } else if (expected.call({}, actual) === true) { 304 | return true; 305 | } 306 | 307 | return false; 308 | } 309 | 310 | function _throws(shouldThrow, block, expected, message) { 311 | var actual; 312 | 313 | if (util.isString(expected)) { 314 | message = expected; 315 | expected = null; 316 | } 317 | 318 | try { 319 | block(); 320 | } catch (e) { 321 | actual = e; 322 | } 323 | 324 | message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + 325 | (message ? ' ' + message : '.'); 326 | 327 | if (shouldThrow && !actual) { 328 | fail(actual, expected, 'Missing expected exception' + message); 329 | } 330 | 331 | if (!shouldThrow && expectedException(actual, expected)) { 332 | fail(actual, expected, 'Got unwanted exception' + message); 333 | } 334 | 335 | if ((shouldThrow && actual && expected && 336 | !expectedException(actual, expected)) || (!shouldThrow && actual)) { 337 | throw actual; 338 | } 339 | } 340 | 341 | // 11. Expected to throw an error: 342 | // assert.throws(block, Error_opt, message_opt); 343 | 344 | assert.throws = function(block, /*optional*/error, /*optional*/message) { 345 | _throws.apply(this, [true].concat(pSlice.call(arguments))); 346 | }; 347 | 348 | // EXTENSION! This is annoying to write outside this module. 349 | assert.doesNotThrow = function(block, /*optional*/message) { 350 | _throws.apply(this, [false].concat(pSlice.call(arguments))); 351 | }; 352 | 353 | assert.ifError = function(err) { if (err) {throw err;}}; 354 | 355 | var objectKeys = Object.keys || function (obj) { 356 | var keys = []; 357 | for (var key in obj) { 358 | if (hasOwn.call(obj, key)) keys.push(key); 359 | } 360 | return keys; 361 | }; 362 | 363 | },{"util/":5}],2:[function(_dereq_,module,exports){ 364 | if (typeof Object.create === 'function') { 365 | // implementation from standard node.js 'util' module 366 | module.exports = function inherits(ctor, superCtor) { 367 | ctor.super_ = superCtor 368 | ctor.prototype = Object.create(superCtor.prototype, { 369 | constructor: { 370 | value: ctor, 371 | enumerable: false, 372 | writable: true, 373 | configurable: true 374 | } 375 | }); 376 | }; 377 | } else { 378 | // old school shim for old browsers 379 | module.exports = function inherits(ctor, superCtor) { 380 | ctor.super_ = superCtor 381 | var TempCtor = function () {} 382 | TempCtor.prototype = superCtor.prototype 383 | ctor.prototype = new TempCtor() 384 | ctor.prototype.constructor = ctor 385 | } 386 | } 387 | 388 | },{}],3:[function(_dereq_,module,exports){ 389 | // shim for using process in browser 390 | 391 | var process = module.exports = {}; 392 | 393 | process.nextTick = (function () { 394 | var canSetImmediate = typeof window !== 'undefined' 395 | && window.setImmediate; 396 | var canPost = typeof window !== 'undefined' 397 | && window.postMessage && window.addEventListener 398 | ; 399 | 400 | if (canSetImmediate) { 401 | return function (f) { return window.setImmediate(f) }; 402 | } 403 | 404 | if (canPost) { 405 | var queue = []; 406 | window.addEventListener('message', function (ev) { 407 | var source = ev.source; 408 | if ((source === window || source === null) && ev.data === 'process-tick') { 409 | ev.stopPropagation(); 410 | if (queue.length > 0) { 411 | var fn = queue.shift(); 412 | fn(); 413 | } 414 | } 415 | }, true); 416 | 417 | return function nextTick(fn) { 418 | queue.push(fn); 419 | window.postMessage('process-tick', '*'); 420 | }; 421 | } 422 | 423 | return function nextTick(fn) { 424 | setTimeout(fn, 0); 425 | }; 426 | })(); 427 | 428 | process.title = 'browser'; 429 | process.browser = true; 430 | process.env = {}; 431 | process.argv = []; 432 | 433 | process.binding = function (name) { 434 | throw new Error('process.binding is not supported'); 435 | } 436 | 437 | // TODO(shtylman) 438 | process.cwd = function () { return '/' }; 439 | process.chdir = function (dir) { 440 | throw new Error('process.chdir is not supported'); 441 | }; 442 | 443 | },{}],4:[function(_dereq_,module,exports){ 444 | module.exports = function isBuffer(arg) { 445 | return arg && typeof arg === 'object' 446 | && typeof arg.copy === 'function' 447 | && typeof arg.fill === 'function' 448 | && typeof arg.readUInt8 === 'function'; 449 | } 450 | },{}],5:[function(_dereq_,module,exports){ 451 | (function (process,global){// Copyright Joyent, Inc. and other Node contributors. 452 | // 453 | // Permission is hereby granted, free of charge, to any person obtaining a 454 | // copy of this software and associated documentation files (the 455 | // "Software"), to deal in the Software without restriction, including 456 | // without limitation the rights to use, copy, modify, merge, publish, 457 | // distribute, sublicense, and/or sell copies of the Software, and to permit 458 | // persons to whom the Software is furnished to do so, subject to the 459 | // following conditions: 460 | // 461 | // The above copyright notice and this permission notice shall be included 462 | // in all copies or substantial portions of the Software. 463 | // 464 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 465 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 466 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 467 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 468 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 469 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 470 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 471 | 472 | var formatRegExp = /%[sdj%]/g; 473 | exports.format = function(f) { 474 | if (!isString(f)) { 475 | var objects = []; 476 | for (var i = 0; i < arguments.length; i++) { 477 | objects.push(inspect(arguments[i])); 478 | } 479 | return objects.join(' '); 480 | } 481 | 482 | var i = 1; 483 | var args = arguments; 484 | var len = args.length; 485 | var str = String(f).replace(formatRegExp, function(x) { 486 | if (x === '%%') return '%'; 487 | if (i >= len) return x; 488 | switch (x) { 489 | case '%s': return String(args[i++]); 490 | case '%d': return Number(args[i++]); 491 | case '%j': 492 | try { 493 | return JSON.stringify(args[i++]); 494 | } catch (_) { 495 | return '[Circular]'; 496 | } 497 | default: 498 | return x; 499 | } 500 | }); 501 | for (var x = args[i]; i < len; x = args[++i]) { 502 | if (isNull(x) || !isObject(x)) { 503 | str += ' ' + x; 504 | } else { 505 | str += ' ' + inspect(x); 506 | } 507 | } 508 | return str; 509 | }; 510 | 511 | 512 | // Mark that a method should not be used. 513 | // Returns a modified function which warns once by default. 514 | // If --no-deprecation is set, then it is a no-op. 515 | exports.deprecate = function(fn, msg) { 516 | // Allow for deprecating things in the process of starting up. 517 | if (isUndefined(global.process)) { 518 | return function() { 519 | return exports.deprecate(fn, msg).apply(this, arguments); 520 | }; 521 | } 522 | 523 | if (process.noDeprecation === true) { 524 | return fn; 525 | } 526 | 527 | var warned = false; 528 | function deprecated() { 529 | if (!warned) { 530 | if (process.throwDeprecation) { 531 | throw new Error(msg); 532 | } else if (process.traceDeprecation) { 533 | console.trace(msg); 534 | } else { 535 | console.error(msg); 536 | } 537 | warned = true; 538 | } 539 | return fn.apply(this, arguments); 540 | } 541 | 542 | return deprecated; 543 | }; 544 | 545 | 546 | var debugs = {}; 547 | var debugEnviron; 548 | exports.debuglog = function(set) { 549 | if (isUndefined(debugEnviron)) 550 | debugEnviron = process.env.NODE_DEBUG || ''; 551 | set = set.toUpperCase(); 552 | if (!debugs[set]) { 553 | if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { 554 | var pid = process.pid; 555 | debugs[set] = function() { 556 | var msg = exports.format.apply(exports, arguments); 557 | console.error('%s %d: %s', set, pid, msg); 558 | }; 559 | } else { 560 | debugs[set] = function() {}; 561 | } 562 | } 563 | return debugs[set]; 564 | }; 565 | 566 | 567 | /** 568 | * Echos the value of a value. Trys to print the value out 569 | * in the best way possible given the different types. 570 | * 571 | * @param {Object} obj The object to print out. 572 | * @param {Object} opts Optional options object that alters the output. 573 | */ 574 | /* legacy: obj, showHidden, depth, colors*/ 575 | function inspect(obj, opts) { 576 | // default options 577 | var ctx = { 578 | seen: [], 579 | stylize: stylizeNoColor 580 | }; 581 | // legacy... 582 | if (arguments.length >= 3) ctx.depth = arguments[2]; 583 | if (arguments.length >= 4) ctx.colors = arguments[3]; 584 | if (isBoolean(opts)) { 585 | // legacy... 586 | ctx.showHidden = opts; 587 | } else if (opts) { 588 | // got an "options" object 589 | exports._extend(ctx, opts); 590 | } 591 | // set default options 592 | if (isUndefined(ctx.showHidden)) ctx.showHidden = false; 593 | if (isUndefined(ctx.depth)) ctx.depth = 2; 594 | if (isUndefined(ctx.colors)) ctx.colors = false; 595 | if (isUndefined(ctx.customInspect)) ctx.customInspect = true; 596 | if (ctx.colors) ctx.stylize = stylizeWithColor; 597 | return formatValue(ctx, obj, ctx.depth); 598 | } 599 | exports.inspect = inspect; 600 | 601 | 602 | // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics 603 | inspect.colors = { 604 | 'bold' : [1, 22], 605 | 'italic' : [3, 23], 606 | 'underline' : [4, 24], 607 | 'inverse' : [7, 27], 608 | 'white' : [37, 39], 609 | 'grey' : [90, 39], 610 | 'black' : [30, 39], 611 | 'blue' : [34, 39], 612 | 'cyan' : [36, 39], 613 | 'green' : [32, 39], 614 | 'magenta' : [35, 39], 615 | 'red' : [31, 39], 616 | 'yellow' : [33, 39] 617 | }; 618 | 619 | // Don't use 'blue' not visible on cmd.exe 620 | inspect.styles = { 621 | 'special': 'cyan', 622 | 'number': 'yellow', 623 | 'boolean': 'yellow', 624 | 'undefined': 'grey', 625 | 'null': 'bold', 626 | 'string': 'green', 627 | 'date': 'magenta', 628 | // "name": intentionally not styling 629 | 'regexp': 'red' 630 | }; 631 | 632 | 633 | function stylizeWithColor(str, styleType) { 634 | var style = inspect.styles[styleType]; 635 | 636 | if (style) { 637 | return '\u001b[' + inspect.colors[style][0] + 'm' + str + 638 | '\u001b[' + inspect.colors[style][1] + 'm'; 639 | } else { 640 | return str; 641 | } 642 | } 643 | 644 | 645 | function stylizeNoColor(str, styleType) { 646 | return str; 647 | } 648 | 649 | 650 | function arrayToHash(array) { 651 | var hash = {}; 652 | 653 | array.forEach(function(val, idx) { 654 | hash[val] = true; 655 | }); 656 | 657 | return hash; 658 | } 659 | 660 | 661 | function formatValue(ctx, value, recurseTimes) { 662 | // Provide a hook for user-specified inspect functions. 663 | // Check that value is an object with an inspect function on it 664 | if (ctx.customInspect && 665 | value && 666 | isFunction(value.inspect) && 667 | // Filter out the util module, it's inspect function is special 668 | value.inspect !== exports.inspect && 669 | // Also filter out any prototype objects using the circular check. 670 | !(value.constructor && value.constructor.prototype === value)) { 671 | var ret = value.inspect(recurseTimes, ctx); 672 | if (!isString(ret)) { 673 | ret = formatValue(ctx, ret, recurseTimes); 674 | } 675 | return ret; 676 | } 677 | 678 | // Primitive types cannot have properties 679 | var primitive = formatPrimitive(ctx, value); 680 | if (primitive) { 681 | return primitive; 682 | } 683 | 684 | // Look up the keys of the object. 685 | var keys = Object.keys(value); 686 | var visibleKeys = arrayToHash(keys); 687 | 688 | if (ctx.showHidden) { 689 | keys = Object.getOwnPropertyNames(value); 690 | } 691 | 692 | // IE doesn't make error fields non-enumerable 693 | // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx 694 | if (isError(value) 695 | && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { 696 | return formatError(value); 697 | } 698 | 699 | // Some type of object without properties can be shortcutted. 700 | if (keys.length === 0) { 701 | if (isFunction(value)) { 702 | var name = value.name ? ': ' + value.name : ''; 703 | return ctx.stylize('[Function' + name + ']', 'special'); 704 | } 705 | if (isRegExp(value)) { 706 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 707 | } 708 | if (isDate(value)) { 709 | return ctx.stylize(Date.prototype.toString.call(value), 'date'); 710 | } 711 | if (isError(value)) { 712 | return formatError(value); 713 | } 714 | } 715 | 716 | var base = '', array = false, braces = ['{', '}']; 717 | 718 | // Make Array say that they are Array 719 | if (isArray(value)) { 720 | array = true; 721 | braces = ['[', ']']; 722 | } 723 | 724 | // Make functions say that they are functions 725 | if (isFunction(value)) { 726 | var n = value.name ? ': ' + value.name : ''; 727 | base = ' [Function' + n + ']'; 728 | } 729 | 730 | // Make RegExps say that they are RegExps 731 | if (isRegExp(value)) { 732 | base = ' ' + RegExp.prototype.toString.call(value); 733 | } 734 | 735 | // Make dates with properties first say the date 736 | if (isDate(value)) { 737 | base = ' ' + Date.prototype.toUTCString.call(value); 738 | } 739 | 740 | // Make error with message first say the error 741 | if (isError(value)) { 742 | base = ' ' + formatError(value); 743 | } 744 | 745 | if (keys.length === 0 && (!array || value.length == 0)) { 746 | return braces[0] + base + braces[1]; 747 | } 748 | 749 | if (recurseTimes < 0) { 750 | if (isRegExp(value)) { 751 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 752 | } else { 753 | return ctx.stylize('[Object]', 'special'); 754 | } 755 | } 756 | 757 | ctx.seen.push(value); 758 | 759 | var output; 760 | if (array) { 761 | output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); 762 | } else { 763 | output = keys.map(function(key) { 764 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); 765 | }); 766 | } 767 | 768 | ctx.seen.pop(); 769 | 770 | return reduceToSingleString(output, base, braces); 771 | } 772 | 773 | 774 | function formatPrimitive(ctx, value) { 775 | if (isUndefined(value)) 776 | return ctx.stylize('undefined', 'undefined'); 777 | if (isString(value)) { 778 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') 779 | .replace(/'/g, "\\'") 780 | .replace(/\\"/g, '"') + '\''; 781 | return ctx.stylize(simple, 'string'); 782 | } 783 | if (isNumber(value)) 784 | return ctx.stylize('' + value, 'number'); 785 | if (isBoolean(value)) 786 | return ctx.stylize('' + value, 'boolean'); 787 | // For some reason typeof null is "object", so special case here. 788 | if (isNull(value)) 789 | return ctx.stylize('null', 'null'); 790 | } 791 | 792 | 793 | function formatError(value) { 794 | return '[' + Error.prototype.toString.call(value) + ']'; 795 | } 796 | 797 | 798 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { 799 | var output = []; 800 | for (var i = 0, l = value.length; i < l; ++i) { 801 | if (hasOwnProperty(value, String(i))) { 802 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 803 | String(i), true)); 804 | } else { 805 | output.push(''); 806 | } 807 | } 808 | keys.forEach(function(key) { 809 | if (!key.match(/^\d+$/)) { 810 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 811 | key, true)); 812 | } 813 | }); 814 | return output; 815 | } 816 | 817 | 818 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { 819 | var name, str, desc; 820 | desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; 821 | if (desc.get) { 822 | if (desc.set) { 823 | str = ctx.stylize('[Getter/Setter]', 'special'); 824 | } else { 825 | str = ctx.stylize('[Getter]', 'special'); 826 | } 827 | } else { 828 | if (desc.set) { 829 | str = ctx.stylize('[Setter]', 'special'); 830 | } 831 | } 832 | if (!hasOwnProperty(visibleKeys, key)) { 833 | name = '[' + key + ']'; 834 | } 835 | if (!str) { 836 | if (ctx.seen.indexOf(desc.value) < 0) { 837 | if (isNull(recurseTimes)) { 838 | str = formatValue(ctx, desc.value, null); 839 | } else { 840 | str = formatValue(ctx, desc.value, recurseTimes - 1); 841 | } 842 | if (str.indexOf('\n') > -1) { 843 | if (array) { 844 | str = str.split('\n').map(function(line) { 845 | return ' ' + line; 846 | }).join('\n').substr(2); 847 | } else { 848 | str = '\n' + str.split('\n').map(function(line) { 849 | return ' ' + line; 850 | }).join('\n'); 851 | } 852 | } 853 | } else { 854 | str = ctx.stylize('[Circular]', 'special'); 855 | } 856 | } 857 | if (isUndefined(name)) { 858 | if (array && key.match(/^\d+$/)) { 859 | return str; 860 | } 861 | name = JSON.stringify('' + key); 862 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { 863 | name = name.substr(1, name.length - 2); 864 | name = ctx.stylize(name, 'name'); 865 | } else { 866 | name = name.replace(/'/g, "\\'") 867 | .replace(/\\"/g, '"') 868 | .replace(/(^"|"$)/g, "'"); 869 | name = ctx.stylize(name, 'string'); 870 | } 871 | } 872 | 873 | return name + ': ' + str; 874 | } 875 | 876 | 877 | function reduceToSingleString(output, base, braces) { 878 | var numLinesEst = 0; 879 | var length = output.reduce(function(prev, cur) { 880 | numLinesEst++; 881 | if (cur.indexOf('\n') >= 0) numLinesEst++; 882 | return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; 883 | }, 0); 884 | 885 | if (length > 60) { 886 | return braces[0] + 887 | (base === '' ? '' : base + '\n ') + 888 | ' ' + 889 | output.join(',\n ') + 890 | ' ' + 891 | braces[1]; 892 | } 893 | 894 | return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; 895 | } 896 | 897 | 898 | // NOTE: These type checking functions intentionally don't use `instanceof` 899 | // because it is fragile and can be easily faked with `Object.create()`. 900 | function isArray(ar) { 901 | return Array.isArray(ar); 902 | } 903 | exports.isArray = isArray; 904 | 905 | function isBoolean(arg) { 906 | return typeof arg === 'boolean'; 907 | } 908 | exports.isBoolean = isBoolean; 909 | 910 | function isNull(arg) { 911 | return arg === null; 912 | } 913 | exports.isNull = isNull; 914 | 915 | function isNullOrUndefined(arg) { 916 | return arg == null; 917 | } 918 | exports.isNullOrUndefined = isNullOrUndefined; 919 | 920 | function isNumber(arg) { 921 | return typeof arg === 'number'; 922 | } 923 | exports.isNumber = isNumber; 924 | 925 | function isString(arg) { 926 | return typeof arg === 'string'; 927 | } 928 | exports.isString = isString; 929 | 930 | function isSymbol(arg) { 931 | return typeof arg === 'symbol'; 932 | } 933 | exports.isSymbol = isSymbol; 934 | 935 | function isUndefined(arg) { 936 | return arg === void 0; 937 | } 938 | exports.isUndefined = isUndefined; 939 | 940 | function isRegExp(re) { 941 | return isObject(re) && objectToString(re) === '[object RegExp]'; 942 | } 943 | exports.isRegExp = isRegExp; 944 | 945 | function isObject(arg) { 946 | return typeof arg === 'object' && arg !== null; 947 | } 948 | exports.isObject = isObject; 949 | 950 | function isDate(d) { 951 | return isObject(d) && objectToString(d) === '[object Date]'; 952 | } 953 | exports.isDate = isDate; 954 | 955 | function isError(e) { 956 | return isObject(e) && 957 | (objectToString(e) === '[object Error]' || e instanceof Error); 958 | } 959 | exports.isError = isError; 960 | 961 | function isFunction(arg) { 962 | return typeof arg === 'function'; 963 | } 964 | exports.isFunction = isFunction; 965 | 966 | function isPrimitive(arg) { 967 | return arg === null || 968 | typeof arg === 'boolean' || 969 | typeof arg === 'number' || 970 | typeof arg === 'string' || 971 | typeof arg === 'symbol' || // ES6 symbol 972 | typeof arg === 'undefined'; 973 | } 974 | exports.isPrimitive = isPrimitive; 975 | 976 | exports.isBuffer = _dereq_('./support/isBuffer'); 977 | 978 | function objectToString(o) { 979 | return Object.prototype.toString.call(o); 980 | } 981 | 982 | 983 | function pad(n) { 984 | return n < 10 ? '0' + n.toString(10) : n.toString(10); 985 | } 986 | 987 | 988 | var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 989 | 'Oct', 'Nov', 'Dec']; 990 | 991 | // 26 Feb 16:19:34 992 | function timestamp() { 993 | var d = new Date(); 994 | var time = [pad(d.getHours()), 995 | pad(d.getMinutes()), 996 | pad(d.getSeconds())].join(':'); 997 | return [d.getDate(), months[d.getMonth()], time].join(' '); 998 | } 999 | 1000 | 1001 | // log is just a thin wrapper to console.log that prepends a timestamp 1002 | exports.log = function() { 1003 | console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); 1004 | }; 1005 | 1006 | 1007 | /** 1008 | * Inherit the prototype methods from one constructor into another. 1009 | * 1010 | * The Function.prototype.inherits from lang.js rewritten as a standalone 1011 | * function (not on Function.prototype). NOTE: If this file is to be loaded 1012 | * during bootstrapping this function needs to be rewritten using some native 1013 | * functions as prototype setup using normal JavaScript does not work as 1014 | * expected during bootstrapping (see mirror.js in r114903). 1015 | * 1016 | * @param {function} ctor Constructor function which needs to inherit the 1017 | * prototype. 1018 | * @param {function} superCtor Constructor function to inherit prototype from. 1019 | */ 1020 | exports.inherits = _dereq_('inherits'); 1021 | 1022 | exports._extend = function(origin, add) { 1023 | // Don't do anything if add isn't an object 1024 | if (!add || !isObject(add)) return origin; 1025 | 1026 | var keys = Object.keys(add); 1027 | var i = keys.length; 1028 | while (i--) { 1029 | origin[keys[i]] = add[keys[i]]; 1030 | } 1031 | return origin; 1032 | }; 1033 | 1034 | function hasOwnProperty(obj, prop) { 1035 | return Object.prototype.hasOwnProperty.call(obj, prop); 1036 | } 1037 | }).call(this,_dereq_("/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 1038 | },{"./support/isBuffer":4,"/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":3,"inherits":2}],6:[function(_dereq_,module,exports){ 1039 | var assert = _dereq_('assert'); 1040 | 1041 | module.exports = function() { 1042 | 'use strict'; 1043 | 1044 | var enteredItem; 1045 | 1046 | this.World = _dereq_('../support/world').World; 1047 | 1048 | this.Given(/^I have an empty grocery list view$/, function(callback) { 1049 | this.emptyGroceryListView(); 1050 | assert.equal(this.getGroceryListView().childNodes.length, 0); 1051 | callback(); 1052 | }); 1053 | 1054 | this.When(/^I provide a valid grocery list item name$/, function(callback) { 1055 | enteredItem = this.createGroceryItem(); 1056 | this.enterNewGorceryListItem(enteredItem); 1057 | callback(); 1058 | }); 1059 | 1060 | this.When(/^I select to add an item$/, function(callback) { 1061 | this.clickAddGroceryListItem(); 1062 | callback(); 1063 | }); 1064 | 1065 | this.Then(/^The item is added to the grocery list view$/, function(callback) { 1066 | assert.equal(this.getGroceryListViewItemAtIndex(0), enteredItem, 'Entered item should be first in empty list.'); 1067 | callback(); 1068 | }); 1069 | 1070 | this.Then(/^The item is accessible from the grocery list collection$/, function(callback) { 1071 | assert.equal(this.groceryListApplication.list.getItemIndex(enteredItem), 0, 'Added item should be found at first index.'); 1072 | callback(); 1073 | }); 1074 | 1075 | }; 1076 | },{"../support/world":7,"assert":1}],7:[function(_dereq_,module,exports){ 1077 | (function (process){/*global window, document*/ 1078 | 'use strict'; 1079 | 1080 | var World = function World(callback) { 1081 | 1082 | this.window = process.browser ? window : {}; 1083 | this.app = undefined; 1084 | this.groceryListApplication = undefined; 1085 | 1086 | var defineGlobals = function(w, doc) { 1087 | this.app = w.app; 1088 | }; 1089 | 1090 | this.domload = function(callback) { 1091 | (function(world) { 1092 | if(document.readyState === 'complete') { 1093 | defineGlobals.call(world, window, document); 1094 | callback(); 1095 | } 1096 | else { 1097 | var delegate = document.addEventListener ? 'addEventListener' : 'attachEvent'; 1098 | var eventType = document.addEventListener ? 'load' : 'onload'; 1099 | window[delegate](eventType, function() { 1100 | defineGlobals.call(world, window, document); 1101 | callback(); 1102 | }); 1103 | } 1104 | }(this)); 1105 | }; 1106 | 1107 | this.openGroceryList = function() { 1108 | return this.app.newSession(); 1109 | }; 1110 | this.createGroceryItem = function() { 1111 | return 'apple'; 1112 | }; 1113 | 1114 | this.getGroceryListView = function() { 1115 | return this.groceryListApplication.$listview; 1116 | }; 1117 | 1118 | this.getGroceryListViewItemAtIndex = function(index) { 1119 | return this.groceryListApplication.$listview.childNodes[index].textContent; 1120 | } 1121 | 1122 | this.emptyGroceryListView = function() { 1123 | this.groceryListApplication.empty(); 1124 | }; 1125 | 1126 | this.enterNewGorceryListItem = function(item) { 1127 | this.groceryListApplication.enterNewItem(item); 1128 | }; 1129 | 1130 | this.createClickEvent = function() { 1131 | var event = document.createEvent('MouseEvents'); 1132 | event.initEvent('click', true, false); 1133 | return event; 1134 | }; 1135 | 1136 | this.clickAddGroceryListItem = function() { 1137 | var clickevent = this.createClickEvent(); 1138 | this.groceryListApplication.$addbutton.dispatchEvent(clickevent); 1139 | }; 1140 | 1141 | callback(); 1142 | 1143 | }; 1144 | 1145 | module.exports.World = World;}).call(this,_dereq_("/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) 1146 | },{"/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":3}]},{},[6]) 1147 | (6) 1148 | }); -------------------------------------------------------------------------------- /test/backgroundOpenApplicationSteps.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var n;"undefined"!=typeof window?n=window:"undefined"!=typeof global?n=global:"undefined"!=typeof self&&(n=self),n.backgroundOpenApplicationSteps=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the 'Software'), to 11 | // deal in the Software without restriction, including without limitation the 12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 13 | // sell copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | // when used in node, this will actually load the util module we depend on 27 | // versus loading the builtin util module as happens otherwise 28 | // this is a bug in node module loading as far as I am concerned 29 | var util = _dereq_('util/'); 30 | 31 | var pSlice = Array.prototype.slice; 32 | var hasOwn = Object.prototype.hasOwnProperty; 33 | 34 | // 1. The assert module provides functions that throw 35 | // AssertionError's when particular conditions are not met. The 36 | // assert module must conform to the following interface. 37 | 38 | var assert = module.exports = ok; 39 | 40 | // 2. The AssertionError is defined in assert. 41 | // new assert.AssertionError({ message: message, 42 | // actual: actual, 43 | // expected: expected }) 44 | 45 | assert.AssertionError = function AssertionError(options) { 46 | this.name = 'AssertionError'; 47 | this.actual = options.actual; 48 | this.expected = options.expected; 49 | this.operator = options.operator; 50 | if (options.message) { 51 | this.message = options.message; 52 | this.generatedMessage = false; 53 | } else { 54 | this.message = getMessage(this); 55 | this.generatedMessage = true; 56 | } 57 | var stackStartFunction = options.stackStartFunction || fail; 58 | 59 | if (Error.captureStackTrace) { 60 | Error.captureStackTrace(this, stackStartFunction); 61 | } 62 | else { 63 | // non v8 browsers so we can have a stacktrace 64 | var err = new Error(); 65 | if (err.stack) { 66 | var out = err.stack; 67 | 68 | // try to strip useless frames 69 | var fn_name = stackStartFunction.name; 70 | var idx = out.indexOf('\n' + fn_name); 71 | if (idx >= 0) { 72 | // once we have located the function frame 73 | // we need to strip out everything before it (and its line) 74 | var next_line = out.indexOf('\n', idx + 1); 75 | out = out.substring(next_line + 1); 76 | } 77 | 78 | this.stack = out; 79 | } 80 | } 81 | }; 82 | 83 | // assert.AssertionError instanceof Error 84 | util.inherits(assert.AssertionError, Error); 85 | 86 | function replacer(key, value) { 87 | if (util.isUndefined(value)) { 88 | return '' + value; 89 | } 90 | if (util.isNumber(value) && (isNaN(value) || !isFinite(value))) { 91 | return value.toString(); 92 | } 93 | if (util.isFunction(value) || util.isRegExp(value)) { 94 | return value.toString(); 95 | } 96 | return value; 97 | } 98 | 99 | function truncate(s, n) { 100 | if (util.isString(s)) { 101 | return s.length < n ? s : s.slice(0, n); 102 | } else { 103 | return s; 104 | } 105 | } 106 | 107 | function getMessage(self) { 108 | return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + 109 | self.operator + ' ' + 110 | truncate(JSON.stringify(self.expected, replacer), 128); 111 | } 112 | 113 | // At present only the three keys mentioned above are used and 114 | // understood by the spec. Implementations or sub modules can pass 115 | // other keys to the AssertionError's constructor - they will be 116 | // ignored. 117 | 118 | // 3. All of the following functions must throw an AssertionError 119 | // when a corresponding condition is not met, with a message that 120 | // may be undefined if not provided. All assertion methods provide 121 | // both the actual and expected values to the assertion error for 122 | // display purposes. 123 | 124 | function fail(actual, expected, message, operator, stackStartFunction) { 125 | throw new assert.AssertionError({ 126 | message: message, 127 | actual: actual, 128 | expected: expected, 129 | operator: operator, 130 | stackStartFunction: stackStartFunction 131 | }); 132 | } 133 | 134 | // EXTENSION! allows for well behaved errors defined elsewhere. 135 | assert.fail = fail; 136 | 137 | // 4. Pure assertion tests whether a value is truthy, as determined 138 | // by !!guard. 139 | // assert.ok(guard, message_opt); 140 | // This statement is equivalent to assert.equal(true, !!guard, 141 | // message_opt);. To test strictly for the value true, use 142 | // assert.strictEqual(true, guard, message_opt);. 143 | 144 | function ok(value, message) { 145 | if (!value) fail(value, true, message, '==', assert.ok); 146 | } 147 | assert.ok = ok; 148 | 149 | // 5. The equality assertion tests shallow, coercive equality with 150 | // ==. 151 | // assert.equal(actual, expected, message_opt); 152 | 153 | assert.equal = function equal(actual, expected, message) { 154 | if (actual != expected) fail(actual, expected, message, '==', assert.equal); 155 | }; 156 | 157 | // 6. The non-equality assertion tests for whether two objects are not equal 158 | // with != assert.notEqual(actual, expected, message_opt); 159 | 160 | assert.notEqual = function notEqual(actual, expected, message) { 161 | if (actual == expected) { 162 | fail(actual, expected, message, '!=', assert.notEqual); 163 | } 164 | }; 165 | 166 | // 7. The equivalence assertion tests a deep equality relation. 167 | // assert.deepEqual(actual, expected, message_opt); 168 | 169 | assert.deepEqual = function deepEqual(actual, expected, message) { 170 | if (!_deepEqual(actual, expected)) { 171 | fail(actual, expected, message, 'deepEqual', assert.deepEqual); 172 | } 173 | }; 174 | 175 | function _deepEqual(actual, expected) { 176 | // 7.1. All identical values are equivalent, as determined by ===. 177 | if (actual === expected) { 178 | return true; 179 | 180 | } else if (util.isBuffer(actual) && util.isBuffer(expected)) { 181 | if (actual.length != expected.length) return false; 182 | 183 | for (var i = 0; i < actual.length; i++) { 184 | if (actual[i] !== expected[i]) return false; 185 | } 186 | 187 | return true; 188 | 189 | // 7.2. If the expected value is a Date object, the actual value is 190 | // equivalent if it is also a Date object that refers to the same time. 191 | } else if (util.isDate(actual) && util.isDate(expected)) { 192 | return actual.getTime() === expected.getTime(); 193 | 194 | // 7.3 If the expected value is a RegExp object, the actual value is 195 | // equivalent if it is also a RegExp object with the same source and 196 | // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). 197 | } else if (util.isRegExp(actual) && util.isRegExp(expected)) { 198 | return actual.source === expected.source && 199 | actual.global === expected.global && 200 | actual.multiline === expected.multiline && 201 | actual.lastIndex === expected.lastIndex && 202 | actual.ignoreCase === expected.ignoreCase; 203 | 204 | // 7.4. Other pairs that do not both pass typeof value == 'object', 205 | // equivalence is determined by ==. 206 | } else if (!util.isObject(actual) && !util.isObject(expected)) { 207 | return actual == expected; 208 | 209 | // 7.5 For all other Object pairs, including Array objects, equivalence is 210 | // determined by having the same number of owned properties (as verified 211 | // with Object.prototype.hasOwnProperty.call), the same set of keys 212 | // (although not necessarily the same order), equivalent values for every 213 | // corresponding key, and an identical 'prototype' property. Note: this 214 | // accounts for both named and indexed properties on Arrays. 215 | } else { 216 | return objEquiv(actual, expected); 217 | } 218 | } 219 | 220 | function isArguments(object) { 221 | return Object.prototype.toString.call(object) == '[object Arguments]'; 222 | } 223 | 224 | function objEquiv(a, b) { 225 | if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) 226 | return false; 227 | // an identical 'prototype' property. 228 | if (a.prototype !== b.prototype) return false; 229 | //~~~I've managed to break Object.keys through screwy arguments passing. 230 | // Converting to array solves the problem. 231 | if (isArguments(a)) { 232 | if (!isArguments(b)) { 233 | return false; 234 | } 235 | a = pSlice.call(a); 236 | b = pSlice.call(b); 237 | return _deepEqual(a, b); 238 | } 239 | try { 240 | var ka = objectKeys(a), 241 | kb = objectKeys(b), 242 | key, i; 243 | } catch (e) {//happens when one is a string literal and the other isn't 244 | return false; 245 | } 246 | // having the same number of owned properties (keys incorporates 247 | // hasOwnProperty) 248 | if (ka.length != kb.length) 249 | return false; 250 | //the same set of keys (although not necessarily the same order), 251 | ka.sort(); 252 | kb.sort(); 253 | //~~~cheap key test 254 | for (i = ka.length - 1; i >= 0; i--) { 255 | if (ka[i] != kb[i]) 256 | return false; 257 | } 258 | //equivalent values for every corresponding key, and 259 | //~~~possibly expensive deep test 260 | for (i = ka.length - 1; i >= 0; i--) { 261 | key = ka[i]; 262 | if (!_deepEqual(a[key], b[key])) return false; 263 | } 264 | return true; 265 | } 266 | 267 | // 8. The non-equivalence assertion tests for any deep inequality. 268 | // assert.notDeepEqual(actual, expected, message_opt); 269 | 270 | assert.notDeepEqual = function notDeepEqual(actual, expected, message) { 271 | if (_deepEqual(actual, expected)) { 272 | fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); 273 | } 274 | }; 275 | 276 | // 9. The strict equality assertion tests strict equality, as determined by ===. 277 | // assert.strictEqual(actual, expected, message_opt); 278 | 279 | assert.strictEqual = function strictEqual(actual, expected, message) { 280 | if (actual !== expected) { 281 | fail(actual, expected, message, '===', assert.strictEqual); 282 | } 283 | }; 284 | 285 | // 10. The strict non-equality assertion tests for strict inequality, as 286 | // determined by !==. assert.notStrictEqual(actual, expected, message_opt); 287 | 288 | assert.notStrictEqual = function notStrictEqual(actual, expected, message) { 289 | if (actual === expected) { 290 | fail(actual, expected, message, '!==', assert.notStrictEqual); 291 | } 292 | }; 293 | 294 | function expectedException(actual, expected) { 295 | if (!actual || !expected) { 296 | return false; 297 | } 298 | 299 | if (Object.prototype.toString.call(expected) == '[object RegExp]') { 300 | return expected.test(actual); 301 | } else if (actual instanceof expected) { 302 | return true; 303 | } else if (expected.call({}, actual) === true) { 304 | return true; 305 | } 306 | 307 | return false; 308 | } 309 | 310 | function _throws(shouldThrow, block, expected, message) { 311 | var actual; 312 | 313 | if (util.isString(expected)) { 314 | message = expected; 315 | expected = null; 316 | } 317 | 318 | try { 319 | block(); 320 | } catch (e) { 321 | actual = e; 322 | } 323 | 324 | message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + 325 | (message ? ' ' + message : '.'); 326 | 327 | if (shouldThrow && !actual) { 328 | fail(actual, expected, 'Missing expected exception' + message); 329 | } 330 | 331 | if (!shouldThrow && expectedException(actual, expected)) { 332 | fail(actual, expected, 'Got unwanted exception' + message); 333 | } 334 | 335 | if ((shouldThrow && actual && expected && 336 | !expectedException(actual, expected)) || (!shouldThrow && actual)) { 337 | throw actual; 338 | } 339 | } 340 | 341 | // 11. Expected to throw an error: 342 | // assert.throws(block, Error_opt, message_opt); 343 | 344 | assert.throws = function(block, /*optional*/error, /*optional*/message) { 345 | _throws.apply(this, [true].concat(pSlice.call(arguments))); 346 | }; 347 | 348 | // EXTENSION! This is annoying to write outside this module. 349 | assert.doesNotThrow = function(block, /*optional*/message) { 350 | _throws.apply(this, [false].concat(pSlice.call(arguments))); 351 | }; 352 | 353 | assert.ifError = function(err) { if (err) {throw err;}}; 354 | 355 | var objectKeys = Object.keys || function (obj) { 356 | var keys = []; 357 | for (var key in obj) { 358 | if (hasOwn.call(obj, key)) keys.push(key); 359 | } 360 | return keys; 361 | }; 362 | 363 | },{"util/":5}],2:[function(_dereq_,module,exports){ 364 | if (typeof Object.create === 'function') { 365 | // implementation from standard node.js 'util' module 366 | module.exports = function inherits(ctor, superCtor) { 367 | ctor.super_ = superCtor 368 | ctor.prototype = Object.create(superCtor.prototype, { 369 | constructor: { 370 | value: ctor, 371 | enumerable: false, 372 | writable: true, 373 | configurable: true 374 | } 375 | }); 376 | }; 377 | } else { 378 | // old school shim for old browsers 379 | module.exports = function inherits(ctor, superCtor) { 380 | ctor.super_ = superCtor 381 | var TempCtor = function () {} 382 | TempCtor.prototype = superCtor.prototype 383 | ctor.prototype = new TempCtor() 384 | ctor.prototype.constructor = ctor 385 | } 386 | } 387 | 388 | },{}],3:[function(_dereq_,module,exports){ 389 | // shim for using process in browser 390 | 391 | var process = module.exports = {}; 392 | 393 | process.nextTick = (function () { 394 | var canSetImmediate = typeof window !== 'undefined' 395 | && window.setImmediate; 396 | var canPost = typeof window !== 'undefined' 397 | && window.postMessage && window.addEventListener 398 | ; 399 | 400 | if (canSetImmediate) { 401 | return function (f) { return window.setImmediate(f) }; 402 | } 403 | 404 | if (canPost) { 405 | var queue = []; 406 | window.addEventListener('message', function (ev) { 407 | var source = ev.source; 408 | if ((source === window || source === null) && ev.data === 'process-tick') { 409 | ev.stopPropagation(); 410 | if (queue.length > 0) { 411 | var fn = queue.shift(); 412 | fn(); 413 | } 414 | } 415 | }, true); 416 | 417 | return function nextTick(fn) { 418 | queue.push(fn); 419 | window.postMessage('process-tick', '*'); 420 | }; 421 | } 422 | 423 | return function nextTick(fn) { 424 | setTimeout(fn, 0); 425 | }; 426 | })(); 427 | 428 | process.title = 'browser'; 429 | process.browser = true; 430 | process.env = {}; 431 | process.argv = []; 432 | 433 | process.binding = function (name) { 434 | throw new Error('process.binding is not supported'); 435 | } 436 | 437 | // TODO(shtylman) 438 | process.cwd = function () { return '/' }; 439 | process.chdir = function (dir) { 440 | throw new Error('process.chdir is not supported'); 441 | }; 442 | 443 | },{}],4:[function(_dereq_,module,exports){ 444 | module.exports = function isBuffer(arg) { 445 | return arg && typeof arg === 'object' 446 | && typeof arg.copy === 'function' 447 | && typeof arg.fill === 'function' 448 | && typeof arg.readUInt8 === 'function'; 449 | } 450 | },{}],5:[function(_dereq_,module,exports){ 451 | (function (process,global){// Copyright Joyent, Inc. and other Node contributors. 452 | // 453 | // Permission is hereby granted, free of charge, to any person obtaining a 454 | // copy of this software and associated documentation files (the 455 | // "Software"), to deal in the Software without restriction, including 456 | // without limitation the rights to use, copy, modify, merge, publish, 457 | // distribute, sublicense, and/or sell copies of the Software, and to permit 458 | // persons to whom the Software is furnished to do so, subject to the 459 | // following conditions: 460 | // 461 | // The above copyright notice and this permission notice shall be included 462 | // in all copies or substantial portions of the Software. 463 | // 464 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 465 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 466 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 467 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 468 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 469 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 470 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 471 | 472 | var formatRegExp = /%[sdj%]/g; 473 | exports.format = function(f) { 474 | if (!isString(f)) { 475 | var objects = []; 476 | for (var i = 0; i < arguments.length; i++) { 477 | objects.push(inspect(arguments[i])); 478 | } 479 | return objects.join(' '); 480 | } 481 | 482 | var i = 1; 483 | var args = arguments; 484 | var len = args.length; 485 | var str = String(f).replace(formatRegExp, function(x) { 486 | if (x === '%%') return '%'; 487 | if (i >= len) return x; 488 | switch (x) { 489 | case '%s': return String(args[i++]); 490 | case '%d': return Number(args[i++]); 491 | case '%j': 492 | try { 493 | return JSON.stringify(args[i++]); 494 | } catch (_) { 495 | return '[Circular]'; 496 | } 497 | default: 498 | return x; 499 | } 500 | }); 501 | for (var x = args[i]; i < len; x = args[++i]) { 502 | if (isNull(x) || !isObject(x)) { 503 | str += ' ' + x; 504 | } else { 505 | str += ' ' + inspect(x); 506 | } 507 | } 508 | return str; 509 | }; 510 | 511 | 512 | // Mark that a method should not be used. 513 | // Returns a modified function which warns once by default. 514 | // If --no-deprecation is set, then it is a no-op. 515 | exports.deprecate = function(fn, msg) { 516 | // Allow for deprecating things in the process of starting up. 517 | if (isUndefined(global.process)) { 518 | return function() { 519 | return exports.deprecate(fn, msg).apply(this, arguments); 520 | }; 521 | } 522 | 523 | if (process.noDeprecation === true) { 524 | return fn; 525 | } 526 | 527 | var warned = false; 528 | function deprecated() { 529 | if (!warned) { 530 | if (process.throwDeprecation) { 531 | throw new Error(msg); 532 | } else if (process.traceDeprecation) { 533 | console.trace(msg); 534 | } else { 535 | console.error(msg); 536 | } 537 | warned = true; 538 | } 539 | return fn.apply(this, arguments); 540 | } 541 | 542 | return deprecated; 543 | }; 544 | 545 | 546 | var debugs = {}; 547 | var debugEnviron; 548 | exports.debuglog = function(set) { 549 | if (isUndefined(debugEnviron)) 550 | debugEnviron = process.env.NODE_DEBUG || ''; 551 | set = set.toUpperCase(); 552 | if (!debugs[set]) { 553 | if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { 554 | var pid = process.pid; 555 | debugs[set] = function() { 556 | var msg = exports.format.apply(exports, arguments); 557 | console.error('%s %d: %s', set, pid, msg); 558 | }; 559 | } else { 560 | debugs[set] = function() {}; 561 | } 562 | } 563 | return debugs[set]; 564 | }; 565 | 566 | 567 | /** 568 | * Echos the value of a value. Trys to print the value out 569 | * in the best way possible given the different types. 570 | * 571 | * @param {Object} obj The object to print out. 572 | * @param {Object} opts Optional options object that alters the output. 573 | */ 574 | /* legacy: obj, showHidden, depth, colors*/ 575 | function inspect(obj, opts) { 576 | // default options 577 | var ctx = { 578 | seen: [], 579 | stylize: stylizeNoColor 580 | }; 581 | // legacy... 582 | if (arguments.length >= 3) ctx.depth = arguments[2]; 583 | if (arguments.length >= 4) ctx.colors = arguments[3]; 584 | if (isBoolean(opts)) { 585 | // legacy... 586 | ctx.showHidden = opts; 587 | } else if (opts) { 588 | // got an "options" object 589 | exports._extend(ctx, opts); 590 | } 591 | // set default options 592 | if (isUndefined(ctx.showHidden)) ctx.showHidden = false; 593 | if (isUndefined(ctx.depth)) ctx.depth = 2; 594 | if (isUndefined(ctx.colors)) ctx.colors = false; 595 | if (isUndefined(ctx.customInspect)) ctx.customInspect = true; 596 | if (ctx.colors) ctx.stylize = stylizeWithColor; 597 | return formatValue(ctx, obj, ctx.depth); 598 | } 599 | exports.inspect = inspect; 600 | 601 | 602 | // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics 603 | inspect.colors = { 604 | 'bold' : [1, 22], 605 | 'italic' : [3, 23], 606 | 'underline' : [4, 24], 607 | 'inverse' : [7, 27], 608 | 'white' : [37, 39], 609 | 'grey' : [90, 39], 610 | 'black' : [30, 39], 611 | 'blue' : [34, 39], 612 | 'cyan' : [36, 39], 613 | 'green' : [32, 39], 614 | 'magenta' : [35, 39], 615 | 'red' : [31, 39], 616 | 'yellow' : [33, 39] 617 | }; 618 | 619 | // Don't use 'blue' not visible on cmd.exe 620 | inspect.styles = { 621 | 'special': 'cyan', 622 | 'number': 'yellow', 623 | 'boolean': 'yellow', 624 | 'undefined': 'grey', 625 | 'null': 'bold', 626 | 'string': 'green', 627 | 'date': 'magenta', 628 | // "name": intentionally not styling 629 | 'regexp': 'red' 630 | }; 631 | 632 | 633 | function stylizeWithColor(str, styleType) { 634 | var style = inspect.styles[styleType]; 635 | 636 | if (style) { 637 | return '\u001b[' + inspect.colors[style][0] + 'm' + str + 638 | '\u001b[' + inspect.colors[style][1] + 'm'; 639 | } else { 640 | return str; 641 | } 642 | } 643 | 644 | 645 | function stylizeNoColor(str, styleType) { 646 | return str; 647 | } 648 | 649 | 650 | function arrayToHash(array) { 651 | var hash = {}; 652 | 653 | array.forEach(function(val, idx) { 654 | hash[val] = true; 655 | }); 656 | 657 | return hash; 658 | } 659 | 660 | 661 | function formatValue(ctx, value, recurseTimes) { 662 | // Provide a hook for user-specified inspect functions. 663 | // Check that value is an object with an inspect function on it 664 | if (ctx.customInspect && 665 | value && 666 | isFunction(value.inspect) && 667 | // Filter out the util module, it's inspect function is special 668 | value.inspect !== exports.inspect && 669 | // Also filter out any prototype objects using the circular check. 670 | !(value.constructor && value.constructor.prototype === value)) { 671 | var ret = value.inspect(recurseTimes, ctx); 672 | if (!isString(ret)) { 673 | ret = formatValue(ctx, ret, recurseTimes); 674 | } 675 | return ret; 676 | } 677 | 678 | // Primitive types cannot have properties 679 | var primitive = formatPrimitive(ctx, value); 680 | if (primitive) { 681 | return primitive; 682 | } 683 | 684 | // Look up the keys of the object. 685 | var keys = Object.keys(value); 686 | var visibleKeys = arrayToHash(keys); 687 | 688 | if (ctx.showHidden) { 689 | keys = Object.getOwnPropertyNames(value); 690 | } 691 | 692 | // IE doesn't make error fields non-enumerable 693 | // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx 694 | if (isError(value) 695 | && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { 696 | return formatError(value); 697 | } 698 | 699 | // Some type of object without properties can be shortcutted. 700 | if (keys.length === 0) { 701 | if (isFunction(value)) { 702 | var name = value.name ? ': ' + value.name : ''; 703 | return ctx.stylize('[Function' + name + ']', 'special'); 704 | } 705 | if (isRegExp(value)) { 706 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 707 | } 708 | if (isDate(value)) { 709 | return ctx.stylize(Date.prototype.toString.call(value), 'date'); 710 | } 711 | if (isError(value)) { 712 | return formatError(value); 713 | } 714 | } 715 | 716 | var base = '', array = false, braces = ['{', '}']; 717 | 718 | // Make Array say that they are Array 719 | if (isArray(value)) { 720 | array = true; 721 | braces = ['[', ']']; 722 | } 723 | 724 | // Make functions say that they are functions 725 | if (isFunction(value)) { 726 | var n = value.name ? ': ' + value.name : ''; 727 | base = ' [Function' + n + ']'; 728 | } 729 | 730 | // Make RegExps say that they are RegExps 731 | if (isRegExp(value)) { 732 | base = ' ' + RegExp.prototype.toString.call(value); 733 | } 734 | 735 | // Make dates with properties first say the date 736 | if (isDate(value)) { 737 | base = ' ' + Date.prototype.toUTCString.call(value); 738 | } 739 | 740 | // Make error with message first say the error 741 | if (isError(value)) { 742 | base = ' ' + formatError(value); 743 | } 744 | 745 | if (keys.length === 0 && (!array || value.length == 0)) { 746 | return braces[0] + base + braces[1]; 747 | } 748 | 749 | if (recurseTimes < 0) { 750 | if (isRegExp(value)) { 751 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 752 | } else { 753 | return ctx.stylize('[Object]', 'special'); 754 | } 755 | } 756 | 757 | ctx.seen.push(value); 758 | 759 | var output; 760 | if (array) { 761 | output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); 762 | } else { 763 | output = keys.map(function(key) { 764 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); 765 | }); 766 | } 767 | 768 | ctx.seen.pop(); 769 | 770 | return reduceToSingleString(output, base, braces); 771 | } 772 | 773 | 774 | function formatPrimitive(ctx, value) { 775 | if (isUndefined(value)) 776 | return ctx.stylize('undefined', 'undefined'); 777 | if (isString(value)) { 778 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') 779 | .replace(/'/g, "\\'") 780 | .replace(/\\"/g, '"') + '\''; 781 | return ctx.stylize(simple, 'string'); 782 | } 783 | if (isNumber(value)) 784 | return ctx.stylize('' + value, 'number'); 785 | if (isBoolean(value)) 786 | return ctx.stylize('' + value, 'boolean'); 787 | // For some reason typeof null is "object", so special case here. 788 | if (isNull(value)) 789 | return ctx.stylize('null', 'null'); 790 | } 791 | 792 | 793 | function formatError(value) { 794 | return '[' + Error.prototype.toString.call(value) + ']'; 795 | } 796 | 797 | 798 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { 799 | var output = []; 800 | for (var i = 0, l = value.length; i < l; ++i) { 801 | if (hasOwnProperty(value, String(i))) { 802 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 803 | String(i), true)); 804 | } else { 805 | output.push(''); 806 | } 807 | } 808 | keys.forEach(function(key) { 809 | if (!key.match(/^\d+$/)) { 810 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 811 | key, true)); 812 | } 813 | }); 814 | return output; 815 | } 816 | 817 | 818 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { 819 | var name, str, desc; 820 | desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; 821 | if (desc.get) { 822 | if (desc.set) { 823 | str = ctx.stylize('[Getter/Setter]', 'special'); 824 | } else { 825 | str = ctx.stylize('[Getter]', 'special'); 826 | } 827 | } else { 828 | if (desc.set) { 829 | str = ctx.stylize('[Setter]', 'special'); 830 | } 831 | } 832 | if (!hasOwnProperty(visibleKeys, key)) { 833 | name = '[' + key + ']'; 834 | } 835 | if (!str) { 836 | if (ctx.seen.indexOf(desc.value) < 0) { 837 | if (isNull(recurseTimes)) { 838 | str = formatValue(ctx, desc.value, null); 839 | } else { 840 | str = formatValue(ctx, desc.value, recurseTimes - 1); 841 | } 842 | if (str.indexOf('\n') > -1) { 843 | if (array) { 844 | str = str.split('\n').map(function(line) { 845 | return ' ' + line; 846 | }).join('\n').substr(2); 847 | } else { 848 | str = '\n' + str.split('\n').map(function(line) { 849 | return ' ' + line; 850 | }).join('\n'); 851 | } 852 | } 853 | } else { 854 | str = ctx.stylize('[Circular]', 'special'); 855 | } 856 | } 857 | if (isUndefined(name)) { 858 | if (array && key.match(/^\d+$/)) { 859 | return str; 860 | } 861 | name = JSON.stringify('' + key); 862 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { 863 | name = name.substr(1, name.length - 2); 864 | name = ctx.stylize(name, 'name'); 865 | } else { 866 | name = name.replace(/'/g, "\\'") 867 | .replace(/\\"/g, '"') 868 | .replace(/(^"|"$)/g, "'"); 869 | name = ctx.stylize(name, 'string'); 870 | } 871 | } 872 | 873 | return name + ': ' + str; 874 | } 875 | 876 | 877 | function reduceToSingleString(output, base, braces) { 878 | var numLinesEst = 0; 879 | var length = output.reduce(function(prev, cur) { 880 | numLinesEst++; 881 | if (cur.indexOf('\n') >= 0) numLinesEst++; 882 | return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; 883 | }, 0); 884 | 885 | if (length > 60) { 886 | return braces[0] + 887 | (base === '' ? '' : base + '\n ') + 888 | ' ' + 889 | output.join(',\n ') + 890 | ' ' + 891 | braces[1]; 892 | } 893 | 894 | return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; 895 | } 896 | 897 | 898 | // NOTE: These type checking functions intentionally don't use `instanceof` 899 | // because it is fragile and can be easily faked with `Object.create()`. 900 | function isArray(ar) { 901 | return Array.isArray(ar); 902 | } 903 | exports.isArray = isArray; 904 | 905 | function isBoolean(arg) { 906 | return typeof arg === 'boolean'; 907 | } 908 | exports.isBoolean = isBoolean; 909 | 910 | function isNull(arg) { 911 | return arg === null; 912 | } 913 | exports.isNull = isNull; 914 | 915 | function isNullOrUndefined(arg) { 916 | return arg == null; 917 | } 918 | exports.isNullOrUndefined = isNullOrUndefined; 919 | 920 | function isNumber(arg) { 921 | return typeof arg === 'number'; 922 | } 923 | exports.isNumber = isNumber; 924 | 925 | function isString(arg) { 926 | return typeof arg === 'string'; 927 | } 928 | exports.isString = isString; 929 | 930 | function isSymbol(arg) { 931 | return typeof arg === 'symbol'; 932 | } 933 | exports.isSymbol = isSymbol; 934 | 935 | function isUndefined(arg) { 936 | return arg === void 0; 937 | } 938 | exports.isUndefined = isUndefined; 939 | 940 | function isRegExp(re) { 941 | return isObject(re) && objectToString(re) === '[object RegExp]'; 942 | } 943 | exports.isRegExp = isRegExp; 944 | 945 | function isObject(arg) { 946 | return typeof arg === 'object' && arg !== null; 947 | } 948 | exports.isObject = isObject; 949 | 950 | function isDate(d) { 951 | return isObject(d) && objectToString(d) === '[object Date]'; 952 | } 953 | exports.isDate = isDate; 954 | 955 | function isError(e) { 956 | return isObject(e) && 957 | (objectToString(e) === '[object Error]' || e instanceof Error); 958 | } 959 | exports.isError = isError; 960 | 961 | function isFunction(arg) { 962 | return typeof arg === 'function'; 963 | } 964 | exports.isFunction = isFunction; 965 | 966 | function isPrimitive(arg) { 967 | return arg === null || 968 | typeof arg === 'boolean' || 969 | typeof arg === 'number' || 970 | typeof arg === 'string' || 971 | typeof arg === 'symbol' || // ES6 symbol 972 | typeof arg === 'undefined'; 973 | } 974 | exports.isPrimitive = isPrimitive; 975 | 976 | exports.isBuffer = _dereq_('./support/isBuffer'); 977 | 978 | function objectToString(o) { 979 | return Object.prototype.toString.call(o); 980 | } 981 | 982 | 983 | function pad(n) { 984 | return n < 10 ? '0' + n.toString(10) : n.toString(10); 985 | } 986 | 987 | 988 | var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 989 | 'Oct', 'Nov', 'Dec']; 990 | 991 | // 26 Feb 16:19:34 992 | function timestamp() { 993 | var d = new Date(); 994 | var time = [pad(d.getHours()), 995 | pad(d.getMinutes()), 996 | pad(d.getSeconds())].join(':'); 997 | return [d.getDate(), months[d.getMonth()], time].join(' '); 998 | } 999 | 1000 | 1001 | // log is just a thin wrapper to console.log that prepends a timestamp 1002 | exports.log = function() { 1003 | console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); 1004 | }; 1005 | 1006 | 1007 | /** 1008 | * Inherit the prototype methods from one constructor into another. 1009 | * 1010 | * The Function.prototype.inherits from lang.js rewritten as a standalone 1011 | * function (not on Function.prototype). NOTE: If this file is to be loaded 1012 | * during bootstrapping this function needs to be rewritten using some native 1013 | * functions as prototype setup using normal JavaScript does not work as 1014 | * expected during bootstrapping (see mirror.js in r114903). 1015 | * 1016 | * @param {function} ctor Constructor function which needs to inherit the 1017 | * prototype. 1018 | * @param {function} superCtor Constructor function to inherit prototype from. 1019 | */ 1020 | exports.inherits = _dereq_('inherits'); 1021 | 1022 | exports._extend = function(origin, add) { 1023 | // Don't do anything if add isn't an object 1024 | if (!add || !isObject(add)) return origin; 1025 | 1026 | var keys = Object.keys(add); 1027 | var i = keys.length; 1028 | while (i--) { 1029 | origin[keys[i]] = add[keys[i]]; 1030 | } 1031 | return origin; 1032 | }; 1033 | 1034 | function hasOwnProperty(obj, prop) { 1035 | return Object.prototype.hasOwnProperty.call(obj, prop); 1036 | } 1037 | }).call(this,_dereq_("/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 1038 | },{"./support/isBuffer":4,"/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":3,"inherits":2}],6:[function(_dereq_,module,exports){ 1039 | 'use strict'; 1040 | var assert = _dereq_('assert'); 1041 | 1042 | module.exports = function() { 1043 | 1044 | this.World = _dereq_('../support/world').World; 1045 | 1046 | this.Given(/^I have opened the grocery list application$/, function(callback) { 1047 | (function(world) { 1048 | world.domload(function() { 1049 | world.groceryListApplication = world.openGroceryList(); 1050 | assert(world.groceryListApplication, 'Grocery List Application is required to be open for editability.'); 1051 | callback(); 1052 | }); 1053 | }(this)); 1054 | }); 1055 | 1056 | }; 1057 | },{"../support/world":7,"assert":1}],7:[function(_dereq_,module,exports){ 1058 | (function (process){/*global window, document*/ 1059 | 'use strict'; 1060 | 1061 | var World = function World(callback) { 1062 | 1063 | this.window = process.browser ? window : {}; 1064 | this.app = undefined; 1065 | this.groceryListApplication = undefined; 1066 | 1067 | var defineGlobals = function(w, doc) { 1068 | this.app = w.app; 1069 | }; 1070 | 1071 | this.domload = function(callback) { 1072 | (function(world) { 1073 | if(document.readyState === 'complete') { 1074 | defineGlobals.call(world, window, document); 1075 | callback(); 1076 | } 1077 | else { 1078 | var delegate = document.addEventListener ? 'addEventListener' : 'attachEvent'; 1079 | var eventType = document.addEventListener ? 'load' : 'onload'; 1080 | window[delegate](eventType, function() { 1081 | defineGlobals.call(world, window, document); 1082 | callback(); 1083 | }); 1084 | } 1085 | }(this)); 1086 | }; 1087 | 1088 | this.openGroceryList = function() { 1089 | return this.app.newSession(); 1090 | }; 1091 | this.createGroceryItem = function() { 1092 | return 'apple'; 1093 | }; 1094 | 1095 | this.getGroceryListView = function() { 1096 | return this.groceryListApplication.$listview; 1097 | }; 1098 | 1099 | this.getGroceryListViewItemAtIndex = function(index) { 1100 | return this.groceryListApplication.$listview.childNodes[index].textContent; 1101 | } 1102 | 1103 | this.emptyGroceryListView = function() { 1104 | this.groceryListApplication.empty(); 1105 | }; 1106 | 1107 | this.enterNewGorceryListItem = function(item) { 1108 | this.groceryListApplication.enterNewItem(item); 1109 | }; 1110 | 1111 | this.createClickEvent = function() { 1112 | var event = document.createEvent('MouseEvents'); 1113 | event.initEvent('click', true, false); 1114 | return event; 1115 | }; 1116 | 1117 | this.clickAddGroceryListItem = function() { 1118 | var clickevent = this.createClickEvent(); 1119 | this.groceryListApplication.$addbutton.dispatchEvent(clickevent); 1120 | }; 1121 | 1122 | callback(); 1123 | 1124 | }; 1125 | 1126 | module.exports.World = World;}).call(this,_dereq_("/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) 1127 | },{"/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":3}]},{},[6]) 1128 | (6) 1129 | }); -------------------------------------------------------------------------------- /test/cucumber-testrunner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 56 |
    57 |
    58 | 59 | 60 | 61 |
    62 | 63 | 64 | -------------------------------------------------------------------------------- /test/features.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.cukefeatures=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o -1) { 62 | if(this.list[index] === value) { 63 | return index; 64 | } 65 | } 66 | return -1; 67 | } 68 | }; 69 | 70 | module.exports = { 71 | create: function() { 72 | return Object.create(groceryList, { 73 | 'list': { 74 | value: [], 75 | writable: false, 76 | enumerable: true 77 | } 78 | }); 79 | } 80 | }; 81 | },{}]},{},[1]) 82 | (1) 83 | }); -------------------------------------------------------------------------------- /test/world.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.world=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { 24 | var fn = queue.shift(); 25 | fn(); 26 | } 27 | } 28 | }, true); 29 | 30 | return function nextTick(fn) { 31 | queue.push(fn); 32 | window.postMessage('process-tick', '*'); 33 | }; 34 | } 35 | 36 | return function nextTick(fn) { 37 | setTimeout(fn, 0); 38 | }; 39 | })(); 40 | 41 | process.title = 'browser'; 42 | process.browser = true; 43 | process.env = {}; 44 | process.argv = []; 45 | 46 | process.binding = function (name) { 47 | throw new Error('process.binding is not supported'); 48 | } 49 | 50 | // TODO(shtylman) 51 | process.cwd = function () { return '/' }; 52 | process.chdir = function (dir) { 53 | throw new Error('process.chdir is not supported'); 54 | }; 55 | 56 | },{}],2:[function(_dereq_,module,exports){ 57 | (function (process){/*global window, document*/ 58 | 'use strict'; 59 | 60 | var World = function World(callback) { 61 | 62 | this.window = process.browser ? window : {}; 63 | this.app = undefined; 64 | this.groceryListApplication = undefined; 65 | 66 | var defineGlobals = function(w, doc) { 67 | this.app = w.app; 68 | }; 69 | 70 | this.domload = function(callback) { 71 | (function(world) { 72 | if(document.readyState === 'complete') { 73 | defineGlobals.call(world, window, document); 74 | callback(); 75 | } 76 | else { 77 | var delegate = document.addEventListener ? 'addEventListener' : 'attachEvent'; 78 | var eventType = document.addEventListener ? 'load' : 'onload'; 79 | window[delegate](eventType, function() { 80 | defineGlobals.call(world, window, document); 81 | callback(); 82 | }); 83 | } 84 | }(this)); 85 | }; 86 | 87 | this.openGroceryList = function() { 88 | return this.app.newSession(); 89 | }; 90 | this.createGroceryItem = function() { 91 | return 'apple'; 92 | }; 93 | 94 | this.getGroceryListView = function() { 95 | return this.groceryListApplication.$listview; 96 | }; 97 | 98 | this.getGroceryListViewItemAtIndex = function(index) { 99 | return this.groceryListApplication.$listview.childNodes[index].textContent; 100 | } 101 | 102 | this.emptyGroceryListView = function() { 103 | this.groceryListApplication.empty(); 104 | }; 105 | 106 | this.enterNewGorceryListItem = function(item) { 107 | this.groceryListApplication.enterNewItem(item); 108 | }; 109 | 110 | this.createClickEvent = function() { 111 | var event = document.createEvent('MouseEvents'); 112 | event.initEvent('click', true, false); 113 | return event; 114 | }; 115 | 116 | this.clickAddGroceryListItem = function() { 117 | var clickevent = this.createClickEvent(); 118 | this.groceryListApplication.$addbutton.dispatchEvent(clickevent); 119 | }; 120 | 121 | callback(); 122 | 123 | }; 124 | 125 | module.exports.World = World;}).call(this,_dereq_("/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) 126 | },{"/Users/toddanderson/Documents/workspace/custardbelly/cucumberjs-browser/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":1}]},{},[2]) 127 | (2) 128 | }); -------------------------------------------------------------------------------- /testem.json: -------------------------------------------------------------------------------- 1 | { 2 | "test_page": "test/cucumber-testrunner.html", 3 | "launchers": { 4 | "Chrome": { 5 | "command": "open http://localhost:7357/test/cucumber-testrunner.html /Applications/Google\\ Chrome.app/", 6 | "protocol": "tap" 7 | }, 8 | "Safari": { 9 | "command": "open http://localhost:7357/test/cucumber-testrunner.html /Applications/Safari.app/", 10 | "protocol": "tap" 11 | }, 12 | "Firefox": { 13 | "command": "open http://localhost:7357/test/cucumber-testrunner.html /Applications/Firefox.app/", 14 | "protocol": "tap" 15 | } 16 | } 17 | } --------------------------------------------------------------------------------