diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..bfa66f4
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,35 @@
+###
+### .editorconfig
+###
+
+
+## Topmost EditorConfig file
+root = true
+
+## UTF8, Unix-style newlines, newline ends every file, trim trailing whitespace
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+## Source code: 2 space indentation
+[*.coffee,*.js]
+indent_style = space
+indent_size = 2
+
+## RAML: 2 space indentation
+[*.raml]
+indent_style = space
+indent_size = 2
+
+## Config files: 2 space indentation
+[*.json,*.yml,*.yaml]
+indent_style = space
+indent_size = 2
+
+## Matches the exact files either package.json or .travis.yml
+[{package.json,.travis.yml}]
+indent_style = space
+indent_size = 2
+
diff --git a/.gitignore b/.gitignore
index a41115d..3c8b9fa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,33 +1,37 @@
-# Mac shit
+###
+### .gitignore
+###
+
+## Mac shit
.DS_Store
-# Logfiles
-logs
-*.log
+## Editor-related tempfiles
+.*.sw[op]
+*~
-# Runtime data
-pids
-*.pid
-*.seed
+## Logfiles
+*.log
+logs/
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
+## Build tool configuration files and intermediate storage
+.grunt/
-# Coverage directory used by tools like istanbul
-coverage
+# Node/npm
+.node_repl_history
+.npm/
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
+## Package dependencies
+node_modules/
-# Compiled binary addons (http://nodejs.org/api/addons.html)
-build/Release
+## Coverage reports and instrumented source
+.nyc_output/
+coverage/
+lib-cov/
+lib/*.js
-# Dependency directory
-# Deployed apps should consider commenting this line out:
-# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
-node_modules
+## `npm pack` artifact
+abao-[0-9]*.[0-9]*.[0-9]*.tgz
-# Generated from CoffeeScript source
-lib/*.js
-tests/unit/*.js
+## dotenv environment variables file
+.env
diff --git a/.markdownlint.json b/.markdownlint.json
new file mode 100644
index 0000000..dcb905f
--- /dev/null
+++ b/.markdownlint.json
@@ -0,0 +1,18 @@
+{
+ "default": true,
+ "header-style": { "style": "atx" },
+ "ul-style": { "style": "asterisk" },
+ "ul-indent": { "indent": 2 },
+ "no-multiple-blanks": { "maximum": 2 },
+ "line-length": { "line_length": 120 },
+ "commands-show-output": false,
+ "ol-prefix": { "style": "one" },
+ "hr-style": { "style": "---" },
+ "proper-names": {
+ "names": [
+ "CoffeeScript",
+ "JavaScript"
+ ],
+ "code_blocks": false
+ }
+}
diff --git a/.npmignore b/.npmignore
index 20b513f..091eb02 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,4 +1,39 @@
-test/
-lib/*.js
+###
+### .npmignore
+###
+
+## Git
+.gitignore
+
+## GitHub
+.github/
+
+## CI configuration files
+.codeclimate.yml
.travis.yml
+wercker.yml
+
+## Build tool configuration files and intermediate storage
+.editorconfig
+.grunt/
+.markdownlint.json
Gruntfile.coffee
+coffeelint.json
+
+## Node/npm
+.node_repl_history
+.npm/
+
+## Coverage reports and instrumented source
+coverage/
+lib/*.js
+
+## Test code and fixtures
+test/
+
+## `npm pack` artifact
+abao-[0-9]*.[0-9]*.[0-9]*.tgz
+
+# dotenv environment variables file
+.env
+
diff --git a/.travis.yml b/.travis.yml
index d3c2098..6bf4916 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,7 +12,7 @@ node_js:
- '6'
- '4'
env:
-- NODE_ENV=development
+ - NODE_ENV=development
notifications:
slack:
secure: fsCX0/TDE9TAJR0S91dboOZ4expmCc8o6joVzsHNJYTJfDtSJehdKjTzYuO/vsRigOOoQZ0dJEPl+D4fysBDV+jkOT5sTjp/uKtcfwHwPi03K8GauwvyW0x4N1M+mY+5jN2ZyBZXqVM5dc0wbgldP9QOg5UpB80hfWUZ+0F1MTM=
@@ -26,11 +26,18 @@ deploy:
repo: cybertk/abao
after_success:
# - grunt coveralls:upload
- - BUILD_DIR="$HOME/build"
- - GITHUB_REPO="cybertk/abao"
- - PROJ_BUILD_DIR="$BUILD_DIR/$GITHUB_REPO"
- - PROJ_COVER_DIR="$PROJ_BUILD_DIR/coverage"
- - COVERAGE_FILE="$PROJ_COVER_DIR/coverage.lcov"
- - COVERALLS_BIN="./node_modules/coveralls/bin/coveralls.js"
+ - COVERAGE_FILE="$TRAVIS_BUILD_DIR/coverage/coverage.lcov"
+ - COVERALLS_BIN="./node_modules/.bin/coveralls"
- $COVERALLS_BIN lib < $COVERAGE_FILE; echo "exit=$?"
+ - echo
+ - echo
+ - echo "===== COMMIT ====="
+ - echo "TRAVIS_REPO_SLUG=$TRAVIS_REPO_SLUG"
+ - echo "TRAVIS_COMMIT=$TRAVIS_COMMIT"
+ - echo "TRAVIS_COMMIT_MESSAGE=$TRAVIS_COMMIT_MESSAGE"
+ - echo "TRAVIS_TAG=$TRAVIS_TAG"
+ - echo "TRAVIS_BRANCH=$TRAVIS_BRANCH"
+ - echo "===== BUILD ====="
+ - echo "TRAVIS_BUILD_NUMBER=$TRAVIS_BUILD_NUMBER"
+ - echo "TRAVIS_BUILD_DIR=$TRAVIS_BUILD_DIR"
diff --git a/Gruntfile.coffee b/Gruntfile.coffee
index d53dbf5..222f759 100644
--- a/Gruntfile.coffee
+++ b/Gruntfile.coffee
@@ -1,5 +1,6 @@
module.exports = (grunt) ->
+ 'use strict'
require('time-grunt') grunt
# Dynamically load npm tasks
@@ -10,6 +11,7 @@ module.exports = (grunt) ->
# Load in the module information
pkg: grunt.file.readJSON 'package.json'
+ readme: 'README.md'
gruntfile: 'Gruntfile.coffee'
clean:
@@ -42,6 +44,8 @@ module.exports = (grunt) ->
]
coffeelint:
+ options:
+ configFile: 'coffeelint.json'
default:
src: [
'lib/*.coffee'
@@ -49,8 +53,14 @@ module.exports = (grunt) ->
]
gruntfile:
src: '<%= gruntfile %>'
+
+ markdownlint:
options:
- configFile: 'coffeelint.json'
+ config: require './.markdownlint.json'
+ default:
+ src: [
+ '<%= readme %>'
+ ]
coffeecov:
transpile:
@@ -84,7 +94,10 @@ module.exports = (grunt) ->
]
grunt.registerTask 'instrument', [ 'coffeecov' ]
- grunt.registerTask 'lint', [ 'coffeelint' ]
+ grunt.registerTask 'lint', [
+ 'coffeelint',
+ 'markdownlint'
+ ]
grunt.registerTask 'test', [
'lint'
diff --git a/README.md b/README.md
index cdfd9af..aa988cb 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
-Automated testing tool based on RAML-0.8
-
# Abao
+RAML-based automated testing tool
+
[![Build Status][Travis-Abao-badge]][Travis-Abao]
-[![Dependency Status][David-AbaoDep-badge]][David-AbaoDep]
-[![devDependency Status][David-AbaoDevDep-badge]][David-AbaoDevDep]
+[![Dependency Status][DavidDM-AbaoDep-badge]][DavidDM-AbaoDep]
+[![devDependency Status][DavidDM-AbaoDevDep-badge]][DavidDM-AbaoDevDep]
[![Coverage Status][Coveralls-Abao-badge]][Coveralls-Abao]
[![Gitter][Gitter-Abao-badge]][Gitter-Abao]
[![CII Best Practices][BestPractices-Abao-badge]][BestPractices-Abao]
@@ -20,13 +20,13 @@ is valid or not.
## Features
-- Verify that each endpoint defined in RAML exists in service
-- Verify that URL params for each endpoint defined in RAML are supported in service
-- Verify that the required query parameters defined in RAML are supported in service
-- Verify that HTTP request headers for each endpoint defined in RAML are supported in service
-- Verify that HTTP request body for each endpoint defined in RAML is supported in service, via [JSONSchema][] validation
-- Verify that HTTP response headers for each endpoint defined in RAML are supported in service
-- Verify that HTTP response body for each endpoint defined in RAML is supported in service, via [JSONSchema][] validation
+* Verify that each endpoint defined in RAML exists in service
+* Verify that URL params for each endpoint defined in RAML are supported in service
+* Verify that the required query parameters defined in RAML are supported in service
+* Verify that HTTP request headers for each endpoint defined in RAML are supported in service
+* Verify that HTTP request body for each endpoint defined in RAML is supported in service, via [JSONSchema][] validation
+* Verify that HTTP response headers for each endpoint defined in RAML are supported in service
+* Verify that HTTP response body for each endpoint defined in RAML is supported in service, via [JSONSchema][] validation
## RAML Support
@@ -93,12 +93,12 @@ the RAML. You can print a list of the generated names with the `--names` flag.
### Example
-The RAML file used in the examples below can be found [here](../master/test/fixtures/single-get.raml).
+The RAML file used in the examples below can be found [here](../master/test/fixtures/machines-single_get.raml).
Get Names:
```bash
-$ abao single-get.raml --names
+$ abao machines-single_get.raml --names
GET /machines -> 200
```
@@ -108,7 +108,7 @@ response code for each path.
```bash
$ ABAO_HOME="/path/to/node_modules/abao"
$ TEMPLATE="${ABAO_HOME}/templates/hookfile.js"
-$ abao single-get.raml --generate-hooks --template="${TEMPLATE}" > test_machines_hooks.js
+$ abao machines-single_get.raml --generate-hooks --template="${TEMPLATE}" > test_machines_hooks.js
```
@@ -155,7 +155,7 @@ after 'GET /machines -> 200', (test, done) ->
Run validation with *JavaScript* hookfile (from above):
```bash
-$ abao single-get.raml --hookfiles=test_machines_hooks.js
+$ abao machines-single_get.raml --hookfiles=test_machines_hooks.js
```
You can also specify what tests **Abao** should skip:
@@ -208,24 +208,27 @@ test 'GET /machines -> 200', (response, body, done) ->
### test.request
-- `server` - Server address, provided from command line.
-- `path` - API endpoint path, parsed from RAML.
-- `method` - HTTP method, parsed from RAML request method (e.g., `get`).
-- `params` - URI parameters, parsed from RAML request `uriParameters` [default: `{}`].
-- `query` - Object containing querystring values to be appended to the `path`,parsed from RAML `queryParameters` section [default: `{}`].
-- `headers` - HTTP headers, parsed from RAML `headers` [default: `{}`].
-- `body` - Entity body for POST, PUT, and PATCH requests. Must be a JSON-serializable object. Parsed from RAML `example` [default: `{}`].
+* `server` - Server address, provided by command line option or parsed from
+ RAML `baseUri`.
+* `path` - API endpoint path, parsed from RAML.
+* `method` - HTTP method, parsed from RAML request method (e.g., `get`).
+* `params` - URI parameters, parsed from RAML request `uriParameters` [default: `{}`].
+* `query` - Object containing querystring values to be appended to the `path`.
+ Parsed from RAML `queryParameters` section [default: `{}`].
+* `headers` - HTTP headers, parsed from RAML `headers` [default: `{}`].
+* `body` - Entity body for POST, PUT, and PATCH requests. Must be a
+ JSON-serializable object. Parsed from RAML `example` [default: `{}`].
### test.response
-- `status` - Expected HTTP response code, parsed from RAML response status.
-- `schema` - Expected schema of HTTP response body, parsed from RAML response `schema`.
-- `headers` - Object containing HTTP response headers from server [default: `{}`].
-- `body` - HTTP response body (JSON-format) from server [default: `null`].
+* `status` - Expected HTTP response code, parsed from RAML response status.
+* `schema` - Expected schema of HTTP response body, parsed from RAML response `schema`.
+* `headers` - Object containing HTTP response headers from server [default: `{}`].
+* `body` - HTTP response body (JSON-format) from server [default: `null`].
## Command Line Options
-```
+```console
Usage:
abao [OPTIONS]
@@ -273,6 +276,11 @@ $ npm test
**Abao** is always looking for new ideas to make the codebase useful.
If you think of something that would make life easier, please submit an issue.
+```bash
+$ npm issues abao
+```
+
+
[//]: # (Cross reference section)
[RAML]: https://raml.org/
@@ -285,10 +293,10 @@ If you think of something that would make life easier, please submit an issue.
[Travis-Abao]: https://travis-ci.org/cybertk/abao/
[Travis-Abao-badge]: https://img.shields.io/travis/cybertk/abao.svg?style=flat
-[David-AbaoDep]: https://david-dm.org/cybertk/abao/
-[David-AbaoDep-badge]: https://david-dm.org/cybertk/abao/status.svg
-[David-AbaoDevDep]: https://david-dm.org/cybertk/abao?type=dev
-[David-AbaoDevDep-badge]: https://david-dm.org/cybertk/abao/dev-status.svg
+[DavidDM-AbaoDep]: https://david-dm.org/cybertk/abao/
+[DavidDM-AbaoDep-badge]: https://david-dm.org/cybertk/abao/status.svg
+[DavidDM-AbaoDevDep]: https://david-dm.org/cybertk/abao?type=dev
+[DavidDM-AbaoDevDep-badge]: https://david-dm.org/cybertk/abao/dev-status.svg
[Coveralls-Abao]: https://coveralls.io/r/cybertk/abao/
[Coveralls-Abao-badge]: https://img.shields.io/coveralls/cybertk/abao.svg
[Gitter-Abao]: https://gitter.im/cybertk/abao/
@@ -298,4 +306,3 @@ If you think of something that would make life easier, please submit an issue.
[NPM-Abao]: https://npmjs.org/package/abao/
[NPM-Abao-badge]: https://nodei.co/npm/abao.png?downloads=true&downloadRank=true&stars=true
-
diff --git a/bin/abao b/bin/abao
index 9671ac2..e4cc1e1 100755
--- a/bin/abao
+++ b/bin/abao
@@ -12,6 +12,5 @@ var path = require('path');
var fs = require('fs');
var libpath = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');
-
-require(libpath + '/cli');
+require(libpath + '/cli').main(process.argv.slice(2));
diff --git a/coffeelint.json b/coffeelint.json
index 362f039..ad370e2 100644
--- a/coffeelint.json
+++ b/coffeelint.json
@@ -1,7 +1,141 @@
{
+ "arrow_spacing": {
+ "level": "warn"
+ },
+ "braces_spacing": {
+ "level": "warn",
+ "spaces": 0,
+ "empty_object_spaces": 0
+ },
+ "camel_case_classes": {
+ "level": "error"
+ },
+ "coffeescript_error": {
+ "level": "error"
+ },
+ "colon_assignment_spacing": {
+ "level": "warn",
+ "spacing": {
+ "left": 0,
+ "right": 1
+ }
+ },
+ "cyclomatic_complexity": {
+ "level": "warn",
+ "value": 10
+ },
+ "duplicate_key": {
+ "level": "error"
+ },
+ "empty_constructor_needs_parens": {
+ "level": "warn"
+ },
+ "ensure_comprehensions": {
+ "level": "warn"
+ },
+ "eol_last": {
+ "level": "ignore"
+ },
+ "indentation": {
+ "value": 2,
+ "level": "error"
+ },
+ "line_endings": {
+ "level": "error",
+ "value": "unix"
+ },
"max_line_length": {
"value": 120,
"level": "error",
"limitComments": true
+ },
+ "missing_fat_arrows": {
+ "level": "warn",
+ "is_strict": false
+ },
+ "newlines_after_classes": {
+ "value": 3,
+ "level": "warn"
+ },
+ "no_backticks": {
+ "level": "error"
+ },
+ "no_debugger": {
+ "level": "warn",
+ "console": false
+ },
+ "no_empty_functions": {
+ "level": "warn"
+ },
+ "no_empty_param_list": {
+ "level": "ignore"
+ },
+ "no_implicit_braces": {
+ "level": "ignore",
+ "strict": true
+ },
+ "no_implicit_parens": {
+ "level": "ignore",
+ "strict": true
+ },
+ "no_interpolation_in_single_quotes": {
+ "level": "warn"
+ },
+ "no_nested_string_interpolation": {
+ "level": "warn"
+ },
+ "no_plusplus": {
+ "level": "ignore"
+ },
+ "no_private_function_fat_arrows": {
+ "level": "warn"
+ },
+ "no_stand_alone_at": {
+ "level": "warn"
+ },
+ "no_tabs": {
+ "level": "error"
+ },
+ "no_this": {
+ "level": "warn"
+ },
+ "no_throwing_strings": {
+ "level": "error"
+ },
+ "no_trailing_semicolons": {
+ "level": "error"
+ },
+ "no_trailing_whitespace": {
+ "level": "error",
+ "allowed_in_comments": false,
+ "allowed_in_empty_lines": false
+ },
+ "no_unnecessary_double_quotes": {
+ "level": "warn"
+ },
+ "no_unnecessary_fat_arrows": {
+ "level": "warn"
+ },
+ "non_empty_constructor_needs_parens": {
+ "level": "ignore"
+ },
+ "prefer_english_operator": {
+ "level": "ignore",
+ "doubleNotLevel": "ignore"
+ },
+ "space_operators": {
+ "level": "warn"
+ },
+ "spacing_after_comma": {
+ "level": "error"
+ },
+ "transform_messes_up_line_numbers": {
+ "level": "warn"
+ },
+ "use_strict": {
+ "module": "coffeelint-use-strict",
+ "level": "warn",
+ "allowGlobal": false,
+ "requireGlobal": false
}
}
diff --git a/lib/abao.coffee b/lib/abao.coffee
index 2941f97..fa03def 100644
--- a/lib/abao.coffee
+++ b/lib/abao.coffee
@@ -2,59 +2,77 @@
# @file Abao class
###
-sms = require("source-map-support").install({handleUncaughtExceptions: false})
-ramlParser = require 'raml-parser'
+require('source-map-support').install({handleUncaughtExceptions: false})
async = require 'async'
+ramlParser = require 'raml-parser'
-options = require './options'
addTests = require './add-tests'
-TestFactory = require './test'
addHooks = require './add-hooks'
-Runner = require './test-runner'
-applyConfiguration = require './apply-configuration'
+asConfiguration = require './configuration'
hooks = require './hooks'
+Runner = require './test-runner'
+TestFactory = require './test'
+
+defaultArgs =
+ _: []
+ options:
+ help: true
class Abao
- constructor: (config) ->
- @configuration = applyConfiguration(config)
+ constructor: (parsedArgs = defaultArgs) ->
+ 'use strict'
+ @configuration = asConfiguration parsedArgs
@tests = []
@hooks = hooks
run: (done) ->
+ 'use strict'
config = @configuration
tests = @tests
hooks = @hooks
- # Inject the JSON refs schemas
- factory = new TestFactory(config.options.schemas)
+ parseHooks = (callback) ->
+ addHooks hooks, config.options.hookfiles, callback
+ return # NOTREACHED
+
+ loadRAML = (callback) ->
+ if !config.ramlPath
+ nofile = new Error 'unspecified RAML file'
+ return callback nofile
+
+ ramlParser.loadFile config.ramlPath
+ .then (raml) ->
+ return callback null, raml
+ .catch (err) ->
+ return callback err
+ return # NOTREACHED
+
+ parseTestsFromRAML = (raml, callback) ->
+ if !config.options.server
+ if raml.baseUri
+ config.options.server = raml.baseUri
+
+ # Inject the JSON refs schemas
+ factory = new TestFactory config.options.schemas
+
+ addTests raml, tests, hooks, callback, factory, config.options.sorted
+ return # NOTREACHED
+
+ runTests = (callback) ->
+ runner = new Runner config.options, config.ramlPath
+ runner.run tests, hooks, callback
+ return # NOTREACHED
async.waterfall [
- # Parse hooks
- (callback) ->
- addHooks hooks, config.options.hookfiles
- callback()
- ,
- # Load RAML
- (callback) ->
- ramlParser.loadFile(config.ramlPath).then (raml) ->
- callback(null, raml)
- , callback
- ,
- # Parse tests from RAML
- (raml, callback) ->
- if !config.options.server
- if raml.baseUri
- config.options.server = raml.baseUri
- addTests raml, tests, hooks, callback, factory, config.options.sorted
- ,
- # Run tests
- (callback) ->
- runner = new Runner config.options, config.ramlPath
- runner.run tests, hooks, callback
+ parseHooks,
+ loadRAML,
+ parseTestsFromRAML,
+ runTests
], done
+ return
+
module.exports = Abao
-module.exports.options = options
diff --git a/lib/add-hooks.coffee b/lib/add-hooks.coffee
index 247c1ad..32320cf 100644
--- a/lib/add-hooks.coffee
+++ b/lib/add-hooks.coffee
@@ -3,32 +3,34 @@
###
require 'coffee-script/register'
-proxyquire = require('proxyquire').noCallThru()
glob = require 'glob'
path = require 'path'
+proxyquire = require('proxyquire').noCallThru()
-addHooks = (hooks, pattern) ->
-
+addHooks = (hooks, pattern, callback) ->
+ 'use strict'
if pattern
files = glob.sync pattern
- console.info 'hook file pattern matches: ' + files
+ if files.length == 0
+ nomatch = new Error "no hook files found matching pattern '#{pattern}'"
+ return callback nomatch
+ console.info 'processing hook file(s):'
try
- for file in files
- proxyquire path.resolve(process.cwd(), file), {
+ files.map (file) ->
+ absFile = path.resolve process.cwd(), file
+ console.info ' ' + absFile
+ proxyquire absFile, {
'hooks': hooks
}
+ console.log()
catch error
- console.error 'skipping hook loading...'
- console.group
- console.error 'error resolving absolute paths of hook files (' + files + ')'
- console.error 'the "--hookfiles" pattern is probably invalid.'
- console.error 'message: ' + error.message if error.message?
- console.error 'stack: ' + error.stack if error.stack?
- console.groupEnd
- return
+ console.error 'error loading hooks...'
+ return callback error
+
+ return callback null
module.exports = addHooks
diff --git a/lib/add-tests.coffee b/lib/add-tests.coffee
index 47aa751..460578e 100644
--- a/lib/add-tests.coffee
+++ b/lib/add-tests.coffee
@@ -3,11 +3,12 @@
###
async = require 'async'
-_ = require 'lodash'
csonschema = require 'csonschema'
+_ = require 'lodash'
parseSchema = (source) ->
+ 'use strict'
if source.contains('$schema')
#jsonschema
# @response.schema = JSON.parse @response.schema
@@ -16,14 +17,24 @@ parseSchema = (source) ->
csonschema.parse source
# @response.schema = csonschema.parse @response.schema
+
parseHeaders = (raml) ->
+ 'use strict'
headers = {}
if raml
for key, v of raml
headers[key] = v.example
headers
+
+getCompatibleMediaTypes = (bodyObj) ->
+ 'use strict'
+ vendorRE = /^application\/(.*\+)?json/i
+ return (type for type of bodyObj when type.match(vendorRE))
+
+
addTests = (raml, tests, hooks, parent, callback, testFactory, sortFirst) ->
+ 'use strict'
# Handle 4th optional param
if _.isFunction(parent)
@@ -120,10 +131,11 @@ addTests = (raml, tests, hooks, parent, callback, testFactory, sortFirst) ->
# Update test.request
test.request.path = path
test.request.method = method
- test.request.headers = parseHeaders(api.headers)
+ test.request.headers = parseHeaders api.headers
- # select compatible content-type in request body (to support vendor tree types, i.e. application/vnd.api+json)
- contentType = (type for type of api.body when type.match(/^application\/(.*\+)?json/i))?[0]
+ # Select compatible content-type in request body to support
+ # vendor tree types (e.g., 'application/vnd.api+json')
+ contentType = getCompatibleMediaTypes(api.body)?[0]
if contentType
test.request.headers['Content-Type'] = contentType
try
@@ -138,13 +150,12 @@ addTests = (raml, tests, hooks, parent, callback, testFactory, sortFirst) ->
test.response.schema = null
if res?.body
- # expect content-type of response body to be identical to request body
+ # Expect content-type of response body to be identical to request body
if contentType && res.body[contentType]?.schema
test.response.schema = parseSchema res.body[contentType].schema
- # otherwise filter in responses section for compatible content-types
- # (vendor tree, i.e. application/vnd.api+json)
+ # Otherwise, filter in responses section for compatible content-types
else
- contentType = (type for type of res.body when type.match(/^application\/(.*\+)?json/i))?[0]
+ contentType = getCompatibleMediaTypes(res.body)?[0]
if res.body[contentType]?.schema
test.response.schema = parseSchema res.body[contentType].schema
diff --git a/lib/apply-configuration.coffee b/lib/apply-configuration.coffee
deleted file mode 100644
index 2bbd129..0000000
--- a/lib/apply-configuration.coffee
+++ /dev/null
@@ -1,58 +0,0 @@
-###*
-# @file Stores command line arguments in configuration object
-###
-
-applyConfiguration = (config) ->
-
- coerceToArray = (value) ->
- if typeof value is 'string'
- value = [value]
- else if !value?
- value = []
- else if value instanceof Array
- value
- else value
- return value
-
- coerceToDict = (value) ->
- array = coerceToArray value
- dict = {}
-
- if array.length > 0
- for item in array
- [key, value] = item.split(':')
- dict[key] = value
-
- return dict
-
- configuration =
- ramlPath: null
- options:
- server: null
- schemas: null
- reporters: false
- reporter: null
- header: null
- names: false
- hookfiles: null
- grep: ''
- invert: false
- 'hooks-only': false
- sorted: false
-
- # Normalize options and config
- for own key, value of config
- configuration[key] = value
-
- # Coerce some options into an dict
- configuration.options.header = coerceToDict(configuration.options.header)
-
- # TODO(quanlong): OAuth2 Bearer Token
- if configuration.options.oauth2Token?
- configuration.options.headers['Authorization'] = "Bearer #{configuration.options.oauth2Token}"
-
- return configuration
-
-
-module.exports = applyConfiguration
-
diff --git a/lib/cli.coffee b/lib/cli.coffee
index 97dca65..3fd9275 100644
--- a/lib/cli.coffee
+++ b/lib/cli.coffee
@@ -4,90 +4,84 @@
require 'coffee-script/register'
+child_process = require 'child_process'
path = require 'path'
_ = require 'lodash'
yargs = require 'yargs'
-Abao = require '../lib/abao'
+
+Abao = require './abao'
+abaoOptions = require './options-abao'
+mochaOptions = require './options-mocha'
pkg = require '../package'
EXIT_SUCCESS = 0
EXIT_FAILURE = 1
showReporters = () ->
- # Copied from node_modules/mocha/_mocha
- console.log()
- console.log ' dot - dot matrix'
- console.log ' doc - html documentation'
- console.log ' spec - hierarchical spec list'
- console.log ' json - single json object'
- console.log ' progress - progress bar'
- console.log ' list - spec-style listing'
- console.log ' tap - test-anything-protocol'
- console.log ' landing - unicode landing strip'
- console.log ' xunit - xunit reporter'
- console.log ' min - minimal reporter (great with --watch)'
- console.log ' json-stream - newline delimited json events'
- console.log ' markdown - markdown documentation (github flavour)'
- console.log ' nyan - nyan cat!'
- console.log()
+ 'use strict'
+ mochaDir = path.dirname require.resolve('mocha')
+ mochaPkg = require 'mocha/package'
+ executable = path.join mochaDir, mochaPkg.bin._mocha
+ executable = path.normalize executable
+ stdoutBuff = child_process.execFileSync executable, ['--reporters']
+ stdout = stdoutBuff.toString()
+ stdout = stdout.slice 0, stdout.length - 1 # Remove last newline
+ console.log stdout
return
-mochaOptionNames = [
- 'grep',
- 'invert'
- 'reporter',
- 'timeout'
-]
-binary = path.basename pkg.bin
-
-argv = yargs
- .usage('Usage:\n ' + binary + ' [OPTIONS]' +
- '\n\nExample:\n ' + binary + ' api.raml --server http://api.example.com')
- .options(Abao.options)
- .group(mochaOptionNames, 'Options passed to Mocha:')
- .implies('template', 'generate-hooks')
- .check((argv) ->
- if argv.reporters == true
- showReporters()
- process.exit EXIT_SUCCESS
-
- # Ensure single positional argument present
- if argv._.length < 1
- throw new Error binary + ': must specify path to RAML file'
- else if argv._.length > 1
- throw new Error binary + ': accepts single positional command-line argument'
-
- return true
- )
- .wrap(80)
- .help('help', 'Show usage information and exit')
- .version().describe('version', 'Show version number and exit')
- .epilog('Website:\n ' + pkg.homepage)
- .argv
-
-aliases = Object.keys(Abao.options).map (key) -> Abao.options[key].alias
- .filter (val) -> val != undefined
-
-configuration =
- 'ramlPath': argv._[0],
- 'options': _.omit argv, ['_', '$0', aliases...]
-
-mochaOptions = _.pick configuration.options, mochaOptionNames
-configuration.options = _.omit configuration.options, mochaOptionNames
-configuration.options.mocha = mochaOptions
-
-abao = new Abao configuration
-
-abao.run (error, nfailures) ->
- if error
- process.exitCode = EXIT_FAILURE
- if error.message
- console.error error.message
- if error.stack
- console.error error.stack
-
- if nfailures > 0
- process.exitCode = EXIT_FAILURE
-
- process.exit()
+parseArgs = (argv) ->
+ 'use strict'
+ allOptions = _.assign {}, abaoOptions, mochaOptions
+ mochaOptionNames = Object.keys mochaOptions
+ prog = path.basename pkg.bin
+ return yargs(argv)
+ .usage("Usage:\n #{prog} [OPTIONS]" +
+ "\n\nExample:\n #{prog} api.raml --server http://api.example.com")
+ .options(allOptions)
+ .group(mochaOptionNames, 'Options passed to Mocha:')
+ .implies('template', 'generate-hooks')
+ .check((argv) ->
+ if argv.reporters == true
+ showReporters()
+ process.exit EXIT_SUCCESS
+
+ # Ensure single positional argument present
+ if argv._.length < 1
+ throw new Error "#{prog}: must specify path to RAML file"
+ else if argv._.length > 1
+ throw new Error "#{prog}: accepts single positional command-line argument"
+
+ return true
+ )
+ .wrap(80)
+ .help('help', 'Show usage information and exit')
+ .version('version', 'Show version number and exit', pkg.version)
+ .epilog("Website:\n #{pkg.homepage}")
+ .argv
+
+##
+## Main
+##
+main = (argv) ->
+ 'use strict'
+ parsedArgs = parseArgs argv
+
+ abao = new Abao parsedArgs
+ abao.run (error, nfailures) ->
+ if error
+ process.exitCode = EXIT_FAILURE
+ if error.message
+ console.error error.message
+ if error.stack
+ console.error error.stack
+
+ if nfailures > 0
+ process.exitCode = EXIT_FAILURE
+
+ process.exit()
+ return # NOTREACHED
+
+
+module.exports =
+ main: main
diff --git a/lib/configuration.coffee b/lib/configuration.coffee
new file mode 100644
index 0000000..4ac93fc
--- /dev/null
+++ b/lib/configuration.coffee
@@ -0,0 +1,97 @@
+###*
+# @file Stores command line arguments in configuration object
+###
+
+_ = require 'lodash'
+path = require 'path'
+
+abaoOptions = require './options-abao'
+mochaOptions = require './options-mocha'
+allOptions = _.assign {}, abaoOptions, mochaOptions
+
+
+applyConfiguration = (config) ->
+ 'use strict'
+
+ coerceToArray = (value) ->
+ if typeof value is 'string'
+ value = [value]
+ else if !value?
+ value = []
+ else if value instanceof Array
+ value
+ else value
+ return value
+
+ coerceToDict = (value) ->
+ array = coerceToArray value
+ dict = {}
+
+ if array.length > 0
+ for item in array
+ [key, value] = item.split(':')
+ dict[key] = value
+
+ return dict
+
+ configuration =
+ ramlPath: null
+ options:
+ server: null
+ schemas: null
+ 'generate-hooks': false
+ template: null
+ timeout: 2000
+ reporter: null
+ header: null
+ names: false
+ hookfiles: null
+ grep: ''
+ invert: false
+ 'hooks-only': false
+ sorted: false
+
+ # Normalize options and config
+ for own key, value of config
+ configuration[key] = value
+
+ # Customize
+ if !configuration.options.template
+ defaultTemplate = path.join 'templates', 'hookfile.js'
+ configuration.options.template = defaultTemplate
+ configuration.options.header = coerceToDict(configuration.options.header)
+
+ # TODO(quanlong): OAuth2 Bearer Token
+ if configuration.options.oauth2Token?
+ configuration.options.headers['Authorization'] = "Bearer #{configuration.options.oauth2Token}"
+
+ return configuration
+
+# Create configuration settings from CLI arguments applied against options
+# @param {Object} parsedArgs - yargs .argv() output
+# @returns {Object} configuration object
+asConfiguration = (parsedArgs) ->
+ 'use strict'
+ ## TODO(plroebuck): Do all configuration in one place...
+ aliases = Object.keys(allOptions).map (key) -> allOptions[key].alias
+ .filter (val) -> val != undefined
+ alreadyHandled = [
+ 'reporters',
+ 'help',
+ 'version'
+ ]
+
+ configuration =
+ ramlPath: parsedArgs._[0],
+ options: _.omit parsedArgs, ['_', '$0', aliases..., alreadyHandled...]
+
+ mochaOptionNames = Object.keys mochaOptions
+ optionsToReparent = _.pick configuration.options, mochaOptionNames
+ configuration.options = _.omit configuration.options, mochaOptionNames
+ configuration.options.mocha = optionsToReparent
+
+ return applyConfiguration configuration
+
+
+module.exports = asConfiguration
+
diff --git a/lib/generate-hooks.coffee b/lib/generate-hooks.coffee
index d16ca0a..f15514a 100644
--- a/lib/generate-hooks.coffee
+++ b/lib/generate-hooks.coffee
@@ -6,6 +6,7 @@ fs = require 'fs'
Mustache = require 'mustache'
generateHooks = (names, ramlFile, templateFile, callback) ->
+ 'use strict'
if !names
callback new Error 'no names found for which to generate hooks'
@@ -19,7 +20,7 @@ generateHooks = (names, ramlFile, templateFile, callback) ->
ramlFile: ramlFile
timestamp: datetime
hooks:
- { 'name': name } for name in names
+ {'name': name} for name in names
view.hooks[0].comment = true
content = Mustache.render template, view
diff --git a/lib/hooks.coffee b/lib/hooks.coffee
index 1ad696f..40349fd 100644
--- a/lib/hooks.coffee
+++ b/lib/hooks.coffee
@@ -8,6 +8,7 @@ _ = require 'lodash'
class Hooks
constructor: () ->
+ 'use strict'
@beforeHooks = {}
@afterHooks = {}
@beforeAllHooks = []
@@ -18,43 +19,54 @@ class Hooks
@skippedTests = []
before: (name, hook) =>
+ 'use strict'
@addHook @beforeHooks, name, hook
after: (name, hook) =>
+ 'use strict'
@addHook @afterHooks, name, hook
beforeAll: (hook) =>
+ 'use strict'
@beforeAllHooks.push hook
afterAll: (hook) =>
+ 'use strict'
@afterAllHooks.push hook
beforeEach: (hook) =>
+ 'use strict'
@beforeEachHooks.push hook
afterEach: (hook) =>
+ 'use strict'
@afterEachHooks.push hook
addHook: (hooks, name, hook) ->
+ 'use strict'
if hooks[name]
hooks[name].push hook
else
hooks[name] = [hook]
test: (name, hook) =>
+ 'use strict'
if @contentTests[name]?
throw new Error "cannot have more than one test with the name: #{name}"
@contentTests[name] = hook
runBeforeAll: (callback) =>
+ 'use strict'
async.series @beforeAllHooks, (err, results) ->
callback(err)
runAfterAll: (callback) =>
+ 'use strict'
async.series @afterAllHooks, (err, results) ->
callback(err)
runBefore: (test, callback) =>
+ 'use strict'
return callback() unless (@beforeHooks[test.name] or @beforeEachHooks)
hooks = @beforeEachHooks.concat(@beforeHooks[test.name] ? [])
@@ -63,6 +75,7 @@ class Hooks
, callback
runAfter: (test, callback) =>
+ 'use strict'
return callback() unless (@afterHooks[test.name] or @afterEachHooks)
hooks = (@afterHooks[test.name] ? []).concat(@afterEachHooks)
@@ -71,14 +84,18 @@ class Hooks
, callback
skip: (name) =>
+ 'use strict'
@skippedTests.push name
hasName: (name) =>
+ 'use strict'
_.has(@beforeHooks, name) || _.has(@afterHooks, name)
skipped: (name) =>
+ 'use strict'
@skippedTests.indexOf(name) != -1
+
module.exports = new Hooks()
diff --git a/lib/options.coffee b/lib/options-abao.coffee
similarity index 58%
rename from lib/options.coffee
rename to lib/options-abao.coffee
index 2fe565c..62b51a6 100644
--- a/lib/options.coffee
+++ b/lib/options-abao.coffee
@@ -1,26 +1,23 @@
###*
-# @file Command line options
+# @file Command line options (Abao-related)
###
-options =
+module.exports =
'generate-hooks':
description: 'Output hooks generated from template file and exit'
type: 'boolean'
- grep:
- alias: 'g'
- description: 'Only run tests matching '
- type: 'string'
-
header:
alias: 'h'
- description: 'Add header to include in each request. Header must be in KEY:VALUE format ' +
- '(e.g., "-h Accept:application/json").\nReuse option to add multiple headers'
+ description: 'Add header to include in each request. Header must be ' +
+ 'in KEY:VALUE format (e.g., "-h Accept:application/json").' +
+ '\nReuse option to add multiple headers'
type: 'string'
hookfiles:
alias: 'f'
- description: 'Specify pattern to match files with before/after hooks for running tests'
+ description: 'Specify pattern to match files with before/after hooks ' +
+ 'for running tests'
type: 'string'
'hooks-only':
@@ -28,32 +25,19 @@ options =
description: 'Run test only if defined either before or after hooks'
type: 'boolean'
- invert:
- alias: 'i'
- description: 'Invert --grep matches'
- type: 'boolean'
-
names:
alias: 'n'
description: 'List names of requests and exit'
type: 'boolean'
- reporter:
- alias: 'R'
- description: 'Specify reporter to use'
- type: 'string'
- default: 'spec'
-
- reporters:
- description: 'Display available reporters and exit'
- type: 'boolean'
-
schemas:
- description: 'Specify pattern to match schema files to be loaded for use as JSON refs'
+ description: 'Specify pattern to match schema files to be loaded for ' +
+ 'use as JSON $refs'
type: 'string'
server:
- description: 'Specify API endpoint to use. The RAML-specified baseUri value will be used if not provided'
+ description: 'Specify API endpoint to use. The RAML-specified baseUri ' +
+ 'value will be used if not provided'
type: 'string'
sorted:
@@ -67,11 +51,3 @@ options =
type: 'string'
normalize: true
- timeout:
- alias: 't'
- description: 'Set test case timeout in milliseconds'
- type: 'number'
- default: 2000
-
-module.exports = options
-
diff --git a/lib/options-mocha.coffee b/lib/options-mocha.coffee
new file mode 100644
index 0000000..26c417e
--- /dev/null
+++ b/lib/options-mocha.coffee
@@ -0,0 +1,31 @@
+###*
+# @file Command line options (Mocha-related)
+###
+
+module.exports =
+ grep:
+ alias: 'g'
+ description: 'Only run tests matching '
+ type: 'string'
+
+ invert:
+ alias: 'i'
+ description: 'Invert --grep matches'
+ type: 'boolean'
+
+ reporter:
+ alias: 'R'
+ description: 'Specify reporter to use'
+ type: 'string'
+ default: 'spec'
+
+ reporters:
+ description: 'Display available reporters and exit'
+ type: 'boolean'
+
+ timeout:
+ alias: 't'
+ description: 'Set test case timeout in milliseconds'
+ type: 'number'
+ default: 2000
+
diff --git a/lib/test-runner.coffee b/lib/test-runner.coffee
index b1f89fd..7d57e51 100644
--- a/lib/test-runner.coffee
+++ b/lib/test-runner.coffee
@@ -2,16 +2,18 @@
# @file TestRunner class
###
-Mocha = require 'mocha'
async = require 'async'
+Mocha = require 'mocha'
path = require 'path'
# TODO(proebuck): Replace underscore module with Lodash; ensure compatibility
_ = require 'underscore'
+
generateHooks = require './generate-hooks'
class TestRunner
constructor: (options, ramlFile) ->
+ 'use strict'
@server = options.server
delete options.server
@mocha = new Mocha options.mocha
@@ -20,6 +22,7 @@ class TestRunner
@ramlFile = ramlFile
addTestToMocha: (test, hooks) =>
+ 'use strict'
mocha = @mocha
options = @options
@@ -62,6 +65,7 @@ class TestRunner
, {test}
run: (tests, hooks, done) ->
+ 'use strict'
server = @server
options = @options
addTestToMocha = @addTestToMocha
@@ -91,11 +95,7 @@ class TestRunner
(callback) ->
if options['generate-hooks']
# Generate hooks skeleton file
- templateFile = if options.template
- options.template
- else
- path.join 'templates', 'hookfile.js'
- generateHooks names, ramlFile, templateFile, done
+ generateHooks names, ramlFile, options.template, done
else if options.names
# Write names to console
console.log name for name in names
@@ -116,5 +116,6 @@ class TestRunner
], done
+
module.exports = TestRunner
diff --git a/lib/test.coffee b/lib/test.coffee
index 7b58a46..43a2e3a 100644
--- a/lib/test.coffee
+++ b/lib/test.coffee
@@ -2,39 +2,42 @@
# @file TestFactory/Test classes
###
-chai = require 'chai'
-request = require 'request'
-_ = require 'underscore'
async = require 'async'
-tv4 = require 'tv4'
+chai = require 'chai'
fs = require 'fs'
glob = require 'glob'
+request = require 'request'
+tv4 = require 'tv4'
+_ = require 'underscore'
assert = chai.assert
String::contains = (it) ->
+ 'use strict'
@indexOf(it) != -1
class TestFactory
constructor: (schemaLocation) ->
+ 'use strict'
if schemaLocation
files = glob.sync schemaLocation
console.log '\tJSON ref schemas: ' + files.join(', ')
- tv4.banUnknown = true
-
for file in files
tv4.addSchema(JSON.parse(fs.readFileSync(file, 'utf8')))
create: (name, contentTest) ->
+ 'use strict'
return new Test(name, contentTest)
+
class Test
constructor: (@name, @contentTest) ->
+ 'use strict'
@name ?= ''
@skip = false
@@ -57,6 +60,7 @@ class Test
done()
url: () ->
+ 'use strict'
path = @request.server + @request.path
for key, value of @request.params
@@ -64,6 +68,7 @@ class Test
return path
run: (callback) ->
+ 'use strict'
assertResponse = @assertResponse
contentTest = @contentTest
@@ -86,6 +91,7 @@ class Test
], callback
assertResponse: (error, response, body) =>
+ 'use strict'
assert.isNull error
assert.isNotNull response, 'Response'
@@ -112,7 +118,12 @@ class Test
"""
json = validateJson()
- result = tv4.validateResult json, schema
+
+ # Validate object against JSON schema
+ checkRecursive = false
+ banUnknown = false
+ result = tv4.validateResult json, schema, checkRecursive, banUnknown
+
assert.lengthOf result.missing, 0, """
Missing/unresolved JSON schema $refs (#{result.missing?.join(', ')}) in schema:
#{JSON.stringify(schema, null, 4)}
diff --git a/package.json b/package.json
index d389dba..2a1357f 100644
--- a/package.json
+++ b/package.json
@@ -1,11 +1,13 @@
{
"name": "abao",
- "version": "0.5.2",
+ "version": "0.5.3",
"description": "RAML testing tool",
"bin": "bin/abao",
"main": "lib/index.js",
"scripts": {
- "commit": "git-cz",
+ "git-cz": "git-cz",
+ "precommit": "npm test",
+ "prepush": "npm test",
"test": "grunt test"
},
"config": {
@@ -13,7 +15,7 @@
"path": "./node_modules/cz-conventional-changelog"
},
"yargs": {
- "camel-case-expansion": false
+ "camel-case-expansion": true
}
},
"repository": {
@@ -62,6 +64,8 @@
"yargs": "^11.1.0"
},
"devDependencies": {
+ "coffeelint-use-strict": "^1.0.0",
+ "commitizen": "^2.9.6",
"coveralls": "^2.11.14",
"cz-conventional-changelog": "^2.1.0",
"express": "^4.12.0",
@@ -72,9 +76,12 @@
"grunt-contrib-clean": "^1.1.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-coveralls": "^1.0.1",
+ "grunt-markdownlint": "^1.1.1",
"grunt-mocha-test": "~0.13.2",
"grunt-shell": "^2.0.0",
+ "husky": "^0.14.3",
"load-grunt-config": "^0.19.2",
+ "markdownlint": "^0.8.0",
"mocha-phantom-coverage-reporter": "^0.1.0",
"mute": "^1.0.0",
"nock": "~9.1.6",
diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee
index e50cc2c..5b64cc5 100644
--- a/test/e2e/cli-test.coffee
+++ b/test/e2e/cli-test.coffee
@@ -1,8 +1,10 @@
-{assert} = require 'chai'
-{exec} = require 'child_process'
+chai = require 'chai'
+child_process = require 'child_process'
express = require 'express'
+_ = require 'lodash'
+pkg = require '../../package'
-pkg = require '../../package.json'
+expect = chai.expect
HOSTNAME = 'localhost'
PORT = 3333
@@ -19,67 +21,107 @@ CMD_PREFIX = ''
ABAO_BIN = './bin/abao'
MOCHA_BIN = './node_modules/mocha/bin/mocha'
+mochaJsonReportKeys = [
+ 'stats',
+ 'tests',
+ 'pending',
+ 'failures',
+ 'passes'
+]
+
stderr = ''
stdout = ''
report = ''
exitStatus = null
-receivedRequest = {}
+#
+# To dump individual raw test results:
+#
+# describe('show me the results', () ->
+# runTestAsync = (done) ->
+# cmd = "#{ABAO_BIN}"
+# execCommand cmd, done
+# before (done) ->
+# debugExecCommand = true
+# runTestAsync done
+# after () ->
+# debugExecCommand = false
+#
+debugExecCommand = false
+
execCommand = (cmd, callback) ->
+ 'use strict'
stderr = ''
stdout = ''
report = ''
exitStatus = null
- cli = exec CMD_PREFIX + cmd, (error, out, err) ->
+ cli = child_process.exec CMD_PREFIX + cmd, (error, out, err) ->
stdout = out
stderr = err
try
report = JSON.parse out
+ catch ignore
+ # Ignore issues with creating report from output
if error
exitStatus = error.code
cli.on 'close', (code) ->
exitStatus = code if exitStatus == null and code != undefined
+ if debugExecCommand
+ console.log "stdout:\n#{stdout}\n"
+ console.log "stderr:\n#{stderr}\n"
+ console.log "report:\n#{report}\n"
+ console.log "exitStatus = #{exitStatus}\n"
callback()
+
describe 'Command line interface', () ->
+ 'use strict'
describe 'when run without any arguments', (done) ->
- before (done) ->
+ runNoArgTestAsync = (done) ->
cmd = "#{ABAO_BIN}"
execCommand cmd, done
- it 'should exit with status 1', () ->
- assert.equal exitStatus, 1
+ before (done) ->
+ runNoArgTestAsync done
it 'should print usage to stderr', () ->
- assert.equal stderr.split('\n')[0], 'Usage:'
+ firstLine = stderr.split('\n')[0]
+ expect(firstLine).to.equal('Usage:')
it 'should print error message to stderr', () ->
- assert.include stderr, 'must specify path to RAML file'
+ expect(stderr).to.include('must specify path to RAML file')
+
+ it 'should exit due to error', () ->
+ expect(exitStatus).to.equal(1)
describe 'when run with multiple positional arguments', (done) ->
- before (done) ->
- ramlFile = "#{RAML_DIR}/single-get.raml"
+ runTooManyArgTestAsync = (done) ->
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
cmd = "#{ABAO_BIN} #{ramlFile} #{ramlFile}"
execCommand cmd, done
- it 'should exit with status 1', () ->
- assert.equal exitStatus, 1
+ before (done) ->
+ runTooManyArgTestAsync done
it 'should print usage to stderr', () ->
- assert.equal stderr.split('\n')[0], 'Usage:'
+ firstLine = stderr.split('\n')[0]
+ expect(firstLine).to.equal('Usage:')
it 'should print error message to stderr', () ->
- assert.include stderr, 'accepts single positional command-line argument'
+ expect(stderr).to.include('accepts single positional command-line argument')
+
+ it 'should exit due to error', () ->
+ expect(exitStatus).to.equal(1)
describe 'when run with one-and-done options', (done) ->
@@ -87,161 +129,204 @@ describe 'Command line interface', () ->
describe 'when RAML argument unnecessary', () ->
describe 'when invoked with "--reporters" option', () ->
+
reporters = ''
- before (done) ->
+ runReportersTestAsync = (done) ->
execCommand "#{MOCHA_BIN} --reporters", () ->
reporters = stdout
execCommand "#{ABAO_BIN} --reporters", done
- it 'exit status should be 0', () ->
- assert.equal exitStatus, 0
+ before (done) ->
+ runReportersTestAsync done
it 'should print same output as `mocha --reporters`', () ->
- assert.equal stdout, reporters
+ expect(stdout).to.equal(reporters)
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
describe 'when invoked with "--version" option', () ->
- before (done) ->
+
+ runVersionTestAsync = (done) ->
cmd = "#{ABAO_BIN} --version"
execCommand cmd, done
- it 'should exit with status 0', () ->
- assert.equal exitStatus, 0
+ before (done) ->
+ runVersionTestAsync done
it 'should print version number to stdout', () ->
- assert.equal stdout.trim(), pkg.version
+ expect(stdout.trim()).to.equal(pkg.version)
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
describe 'when invoked with "--help" option', () ->
- before (done) ->
+
+ runHelpTestAsync = (done) ->
cmd = "#{ABAO_BIN} --help"
execCommand cmd, done
- it 'should exit with status 0', () ->
- assert.equal exitStatus, 0
+ before (done) ->
+ runHelpTestAsync done
it 'should print usage to stdout', () ->
- assert.equal stdout.split('\n')[0], 'Usage:'
+ firstLine = stdout.split('\n')[0]
+ expect(firstLine).to.equal('Usage:')
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
+
describe 'when RAML argument required', () ->
describe 'when invoked with "--names" option', () ->
- before (done) ->
- ramlFile = "#{RAML_DIR}/single-get.raml"
+
+ runNamesTestAsync = (done) ->
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
cmd = "#{ABAO_BIN} #{ramlFile} --names"
execCommand cmd, done
- it 'exit status should be 0', () ->
- assert.equal exitStatus, 0
+ before (done) ->
+ runNamesTestAsync done
it 'should print names', () ->
- assert.include stdout, 'GET /machines -> 200'
+ expect(stdout).to.include('GET /machines -> 200')
it 'should not run tests', () ->
- assert.notInclude stdout, '0 passing'
+ expect(stdout).to.not.include('0 passing')
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
describe 'when invoked with "--generate-hooks" option', () ->
- describe 'by itself', () ->
- before (done) ->
- ramlFile = "#{RAML_DIR}/single-get.raml"
+
+ describe 'by itself (use package-provided template)', () ->
+
+ runGenHooksTestAsync = (done) ->
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
cmd = "#{ABAO_BIN} #{ramlFile} --generate-hooks"
execCommand cmd, done
- it 'exit status should be 0', () ->
- assert.equal exitStatus, 0
+ before (done) ->
+ runGenHooksTestAsync done
it 'should print skeleton hookfile', () ->
- assert.include stdout, '// ABAO hooks file'
+ expect(stdout).to.include('// ABAO hooks file')
it 'should not run tests', () ->
- assert.notInclude stdout, '0 passing'
+ expect(stdout).to.not.include('0 passing')
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
describe 'with "--template" option', () ->
- before (done) ->
+
+ runGenHookTemplateTestAsync = (done) ->
templateFile = "#{TEMPLATE_DIR}/hookfile.js"
- ramlFile = "#{RAML_DIR}/single-get.raml"
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
cmd = "#{ABAO_BIN} #{ramlFile} --generate-hooks --template #{templateFile}"
execCommand cmd, done
- it 'exit status should be 0', () ->
- assert.equal exitStatus, 0
+ before (done) ->
+ runGenHookTemplateTestAsync done
it 'should print skeleton hookfile', () ->
- assert.include stdout, '// ABAO hooks file'
+ expect(stdout).to.include('// ABAO hooks file')
it 'should not run tests', () ->
- assert.notInclude stdout, '0 passing'
+ expect(stdout).to.not.include('0 passing')
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
+
describe 'when invoked with "--template" but without "--generate-hooks" option', () ->
- before (done) ->
+
+ runTemplateOnlyTestAsync = (done) ->
templateFile = "#{TEMPLATE_DIR}/hookfile.js"
- ramlFile = "#{RAML_DIR}/single-get.raml"
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
cmd = "#{ABAO_BIN} #{ramlFile} --template #{templateFile}"
execCommand cmd, done
- it 'exit status should be 1', () ->
- assert.equal exitStatus, 1
+ before (done) ->
+ runTemplateOnlyTestAsync done
it 'should print error message to stderr', () ->
- assert.include stderr, 'Implications failed:'
- assert.include stderr, 'template -> generate-hooks'
+ expect(stderr).to.include('Implications failed:')
+ expect(stderr).to.include('template -> generate-hooks')
+
+ it 'should exit due to error', () ->
+ expect(exitStatus).to.equal(1)
describe 'when RAML file not found', (done) ->
- before (done) ->
+
+ runNoRamlTestAsync = (done) ->
ramlFile = "#{RAML_DIR}/nonexistent_path.raml"
cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER}"
execCommand cmd, done
- it 'should exit with status 1', () ->
- assert.equal exitStatus, 1
+ before (done) ->
+ runNoRamlTestAsync done
it 'should print error message to stderr', () ->
# See https://travis-ci.org/cybertk/abao/jobs/76656192#L479
# iojs behaviour is different from nodejs
- assert.include stderr, 'Error: ENOENT'
+ expect(stderr).to.include('Error: ENOENT')
+
+ it 'should exit due to error', () ->
+ expect(exitStatus).to.equal(1)
describe 'arguments with existing RAML and responding server', () ->
+
describe 'when invoked without "--server" option', () ->
+
describe 'when RAML file does not specify "baseUri"', () ->
- before (done) ->
- ramlFile = "#{RAML_DIR}/no-base-uri.raml"
+
+ runUnspecifiedServerTestAsync = (done) ->
+ ramlFile = "#{RAML_DIR}/music-no_base_uri.raml"
cmd = "#{ABAO_BIN} #{ramlFile} --reporter json"
execCommand cmd, done
- it 'should exit with status 1', () ->
- assert.equal exitStatus, 1
+ before (done) ->
+ runUnspecifiedServerTestAsync done
it 'should print error message to stderr', () ->
- assert.include stderr, 'no API endpoint specified'
+ expect(stderr).to.include('no API endpoint specified')
- describe 'when RAML file does specify "baseUri"', () ->
+ it 'should exit due to error', () ->
+ expect(exitStatus).to.equal(1)
- before (done) ->
- ramlFile = "#{RAML_DIR}/single-get.raml"
+
+ describe 'when RAML file specifies "baseUri"', () ->
+
+ resTestTitle = 'GET /machines -> 200 Validate response code and body'
+
+ runBaseUriServerTestAsync = (done) ->
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
cmd = "#{ABAO_BIN} #{ramlFile} --reporter json"
app = express()
app.get '/machines', (req, res) ->
- res.setHeader 'Content-Type', 'application/json'
machine =
type: 'bulldozer'
name: 'willy'
- response = [machine]
- res.status(200).send response
+ res.status(200).json([machine])
server = app.listen PORT, () ->
execCommand cmd, () ->
@@ -249,30 +334,92 @@ describe 'Command line interface', () ->
server.on 'close', done
- it 'exit status should be 0', () ->
- assert.equal exitStatus, 0
+ before (done) ->
+ runBaseUriServerTestAsync done
it 'should print count of tests run', () ->
- assert.equal 1, report.tests.length
- assert.equal 1, report.passes.length
+ expect(report).to.exist
+ expect(report).to.have.all.keys(mochaJsonReportKeys)
+ expect(report.stats.tests).to.equal(1)
+ expect(report.stats.passes).to.equal(1)
it 'should print correct title for response', () ->
- assert.equal report.tests[0].fullTitle, 'GET /machines -> 200 Validate response code and body'
+ expect(report.tests).to.have.length(1)
+ expect(report.tests[0].fullTitle).to.equal(resTestTitle)
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
+
describe 'when executing the command and the server is responding as specified in the RAML', () ->
- before (done) ->
- ramlFile = "#{RAML_DIR}/single-get.raml"
+
+ responses = {}
+ getResponse = undefined
+ headResponse = undefined
+ optionsResponse = undefined
+
+ getTestTitle = 'GET /machines -> 200 Validate response code and body'
+ headTestTitle = 'HEAD /machines -> 200 Validate response code only'
+ optionsTestTitle = 'OPTIONS /machines -> 204 Validate response code only'
+
+ runNormalTestAsync = (done) ->
+ ramlFile = "#{RAML_DIR}/machines-get_head_options.raml"
cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --reporter json"
app = express()
- app.get '/machines', (req, res) ->
- res.setHeader 'Content-Type', 'application/json'
+ app.use (req, res, next) ->
+ origResWrite = res.write
+ origResEnd = res.end
+ chunks = []
+ res.write = (chunk) ->
+ chunks.push new Buffer(chunk)
+ origResWrite.apply res, arguments
+ res.end = (chunk) ->
+ if (chunk)
+ chunks.push new Buffer(chunk)
+ res.body = Buffer.concat(chunks).toString('utf8')
+ origResEnd.apply res, arguments
+ next()
+
+ app.options '/machines', (req, res, next) ->
+ allow = ['OPTIONS', 'HEAD', 'GET']
+ directives = ['no-cache', 'no-store', 'must-revalidate']
+ res.setHeader 'Allow', allow.join ','
+ res.setHeader 'Cache-Control', directives.join ','
+ res.setHeader 'Pragma', directives[0]
+ res.setHeader 'Expires', '0'
+ res.status(204).end()
+ next()
+
+ app.get '/machines', (req, res, next) ->
machine =
type: 'bulldozer'
name: 'willy'
- response = [machine]
- res.status(200).send response
+ res.status(200).json([machine])
+ next()
+
+ app.use (req, res, next) ->
+ response =
+ headers: {},
+ body: res.body
+ headerNames = do () ->
+ if req.method == 'OPTIONS'
+ return [
+ 'Allow',
+ 'Cache-Control',
+ 'Expires',
+ 'Pragma'
+ ]
+ else
+ return [
+ 'Content-Type',
+ 'Content-Length',
+ 'ETag'
+ ]
+ headerNames.forEach (headerName) ->
+ response.headers[headerName] = res.get headerName
+ responses[req.method] = _.cloneDeep(response)
server = app.listen PORT, () ->
execCommand cmd, () ->
@@ -280,30 +427,64 @@ describe 'Command line interface', () ->
server.on 'close', done
- it 'exit status should be 0', () ->
- assert.equal exitStatus, 0
+ before (done) ->
+ runNormalTestAsync done
+
+ before () ->
+ getResponse = responses['GET']
+ headResponse = responses['HEAD']
+ optionsResponse = responses['OPTIONS']
+
+ it 'should provide count of tests run', () ->
+ expect(report).to.exist
+ expect(report).to.have.all.keys(mochaJsonReportKeys)
+ expect(report.stats.tests).to.equal(3)
+
+ it 'should provide count of tests passing', () ->
+ expect(report.stats.passes).to.equal(3)
+
+ it 'should print correct title for each response', () ->
+ expect(report.tests).to.have.length(3)
+ expect(report.tests[0].fullTitle).to.equal(getTestTitle)
+ expect(report.tests[1].fullTitle).to.equal(headTestTitle)
+ expect(report.tests[2].fullTitle).to.equal(optionsTestTitle)
+
+ it 'OPTIONS response should allow GET and HEAD requests', () ->
+ allow = optionsResponse.headers['Allow']
+ expect(allow).to.equal('OPTIONS,HEAD,GET')
- it 'should print count of tests run', () ->
- assert.equal 1, report.tests.length
- assert.equal 1, report.passes.length
+ it 'OPTIONS response should disable caching of it', () ->
+ cacheControl = optionsResponse.headers['Cache-Control']
+ expect(cacheControl).to.equal('no-cache,no-store,must-revalidate')
+ pragma = optionsResponse.headers['Pragma']
+ expect(pragma).to.equal('no-cache')
+ expires = optionsResponse.headers['Expires']
+ expect(expires).to.equal('0')
+
+ it 'OPTIONS and HEAD responses should not have bodies', () ->
+ expect(optionsResponse.body).to.be.empty
+ expect(headResponse.body).to.be.empty
+
+ it 'GET and HEAD responses should have equivalent headers', () ->
+ expect(getResponse.headers).to.deep.equal(headResponse.headers)
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
- it 'should print correct title for response', () ->
- assert.equal report.tests[0].fullTitle, 'GET /machines -> 200 Validate response code and body'
describe 'when executing the command and RAML includes other RAML files', () ->
- before (done) ->
- ramlFile = "#{RAML_DIR}/include_other_raml.raml"
+
+ runRamlIncludesTestAsync = (done) ->
+ ramlFile = "#{RAML_DIR}/machines-include_other_raml.raml"
cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER}"
app = express()
app.get '/machines', (req, res) ->
- res.setHeader 'Content-Type', 'application/json'
machine =
type: 'bulldozer'
name: 'willy'
- response = [machine]
- res.status(200).send response
+ res.status(200).json([machine])
server = app.listen PORT, () ->
execCommand cmd, () ->
@@ -311,28 +492,31 @@ describe 'Command line interface', () ->
server.on 'close', done
- it 'exit status should be 0', () ->
- assert.equal exitStatus, 0
+ before (done) ->
+ runRamlIncludesTestAsync done
+
+ it 'should print count of passing tests run', () ->
+ expect(stdout).to.have.string('1 passing')
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
- it 'should print count of tests run', () ->
- assert.include stdout, '1 passing'
describe 'when called with arguments', () ->
describe 'when invoked with "--reporter" option', () ->
- before (done) ->
- ramlFile = "#{RAML_DIR}/single-get.raml"
+
+ runReporterTestAsync = (done) ->
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --reporter spec"
app = express()
app.get '/machines', (req, res) ->
- res.setHeader 'Content-Type', 'application/json'
machine =
type: 'bulldozer'
name: 'willy'
- response = [machine]
- res.status(200).send response
+ res.status(200).json([machine])
server = app.listen PORT, () ->
execCommand cmd, () ->
@@ -340,62 +524,121 @@ describe 'Command line interface', () ->
server.on 'close', done
+ before (done) ->
+ runReporterTestAsync done
+
it 'should print using the specified reporter', () ->
- assert.include stdout, '1 passing'
+ expect(stdout).to.have.string('1 passing')
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
+
describe 'when invoked with "--header" option', () ->
receivedRequest = {}
+ producedMediaType = 'application/vnd.api+json'
+ reqMediaType = undefined
+ extraHeader = undefined
- before (done) ->
- ramlFile = "#{RAML_DIR}/single-get.raml"
- cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --header Accept:application/json"
+ describe 'with "Accept" header', () ->
- app = express()
+ runAcceptHeaderTestAsync = (done) ->
+ extraHeader = "Accept:#{reqMediaType}"
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
+ cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --header #{extraHeader}"
- app.get '/machines', (req, res) ->
- receivedRequest = req
- res.setHeader 'Content-Type', 'application/json'
- machine =
- type: 'bulldozer'
- name: 'willy'
- response = [machine]
- res.status(200).send response
+ app = express()
- server = app.listen PORT, () ->
- execCommand cmd, () ->
- server.close()
+ app.use (req, res, next) ->
+ receivedRequest = req
+ next()
- server.on 'close', done
+ app.use (req, res, next) ->
+ err = null
+ if !req.accepts ["#{producedMediaType}"]
+ err = new Error('Not Acceptable')
+ err.status = 406
+ next(err)
- it 'should have an additional header in the request', () ->
- assert.equal receivedRequest.headers.accept, 'application/json'
+ app.get '/machines', (req, res) ->
+ machine =
+ type: 'bulldozer'
+ name: 'willy'
+ res.type "#{producedMediaType}"
+ res.status(200).send([machine])
- it 'exit status should be 0', () ->
- assert.equal exitStatus, 0
+ app.use (err, req, res, next) ->
+ res.status(err.status || 500)
+ .json({
+ message: err.message,
+ stack: err.stack
+ })
+ return
- it 'should print count of tests run', () ->
- assert.include stdout, '1 passing'
+ server = app.listen PORT, () ->
+ execCommand cmd, () ->
+ server.close()
+
+ server.on 'close', done
+
+ context 'when expecting success', () ->
+
+ before (done) ->
+ reqMediaType = "#{producedMediaType}"
+ runAcceptHeaderTestAsync done
+
+ it 'should have the additional header in the request', () ->
+ expect(receivedRequest.headers.accept).to.equal("#{reqMediaType}")
+
+ it 'should print count of passing tests run', () ->
+ expect(stdout).to.have.string('1 passing')
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
+
+
+ context 'when expecting failure', () ->
+
+ before (done) ->
+ reqMediaType = 'application/json'
+ runAcceptHeaderTestAsync done
+
+ it 'should have the additional header in the request', () ->
+ expect(receivedRequest.headers.accept).to.equal("#{reqMediaType}")
+
+ # Errors thrown by Mocha show up in stdout; those by Abao in stderr.
+ it 'Mocha should throw an error', () ->
+ detail = "Error: expected 406 to equal '200'"
+ expect(stdout).to.have.string(detail)
+
+ it 'should run test but not complete', () ->
+ expect(stdout).to.have.string('1 failing')
+
+ it 'should exit due to error', () ->
+ expect(exitStatus).to.equal(1)
describe 'when invoked with "--hookfiles" option', () ->
receivedRequest = {}
- before (done) ->
- ramlFile = "#{RAML_DIR}/single-get.raml"
- cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --hookfiles=#{HOOK_DIR}/*_hooks.*"
+ runHookfilesTestAsync = (done) ->
+ pattern = "#{HOOK_DIR}/*_hooks.*"
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
+ cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --hookfiles=#{pattern}"
app = express()
- app.get '/machines', (req, res) ->
+ app.use (req, res, next) ->
receivedRequest = req
- res.setHeader 'Content-Type', 'application/json'
+ next()
+
+ app.get '/machines', (req, res) ->
machine =
type: 'bulldozer'
name: 'willy'
- response = [machine]
- res.status(200).send response
+ res.status(200).json([machine])
server = app.listen PORT, () ->
execCommand cmd, () ->
@@ -403,29 +646,34 @@ describe 'Command line interface', () ->
server.on 'close', done
+ before (done) ->
+ runHookfilesTestAsync done
+
it 'should modify the transaction with hooks', () ->
- assert.equal receivedRequest.headers['header'], '123232323'
- assert.equal receivedRequest.query['key'], 'value'
+ expect(receivedRequest.headers['header']).to.equal('123232323')
+ expect(receivedRequest.query['key']).to.equal('value')
it 'should print message to stdout and stderr', () ->
- assert.include stdout, 'before-hook-GET-machines'
- assert.include stderr, 'after-hook-GET-machines'
+ expect(stdout).to.include('before-hook-GET-machines')
+ expect(stderr).to.include('after-hook-GET-machines')
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
describe 'when invoked with "--hooks-only" option', () ->
- before (done) ->
- ramlFile = "#{RAML_DIR}/single-get.raml"
+
+ runHooksOnlyTestAsync = (done) ->
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --hooks-only"
app = express()
app.get '/machines', (req, res) ->
- res.setHeader 'Content-Type', 'application/json'
machine =
type: 'bulldozer'
name: 'willy'
- response = [machine]
- res.status(200).send response
+ res.status(200).json([machine])
server = app.listen PORT, () ->
execCommand cmd, () ->
@@ -433,55 +681,97 @@ describe 'Command line interface', () ->
server.on 'close', done
- it 'exit status should be 0', () ->
- assert.equal exitStatus, 0
+ before (done) ->
+ runHooksOnlyTestAsync done
it 'should not run test without hooks', () ->
- assert.include stdout, '1 pending'
+ expect(stdout).to.have.string('1 pending')
+
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
+
describe 'when invoked with "--timeout" option', () ->
- cost = ''
- before (done) ->
- ramlFile = "#{RAML_DIR}/single-get.raml"
- cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --timeout 100"
+ timeout = undefined
+ elapsed = -1
+ finished = undefined
+
+ runTimeoutTestAsync = (done) ->
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
+ cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --timeout #{timeout}"
+
+ beginTime = undefined
+ finished = false
app = express()
- t0 = ''
+ app.use (req, res, next) ->
+ beginTime = new Date()
+ res.on 'finish', () ->
+ finished = true
+ next()
+
+ app.use (req, res, next) ->
+ delay = timeout * 2
+ setTimeout next, delay
+
app.get '/machines', (req, res) ->
- t0 = new Date
+ machine =
+ type: 'bulldozer'
+ name: 'willy'
+ res.status(200).json([machine])
server = app.listen PORT, () ->
execCommand cmd, () ->
- cost = new Date - t0
+ endTime = new Date()
+ if finished
+ elapsed = endTime - beginTime
+ console.log "elapsed = #{elapsed} msecs (req/res)"
server.close()
server.on 'close', done
- it 'exit status should be 1', () ->
- assert.equal exitStatus, 1
- it 'should exit before timeout', () ->
- assert.ok cost < 200
+ context 'given insufficient time to complete', () ->
+
+ before (done) ->
+ timeout = 20
+ console.log "timeout = #{timeout} msecs"
+ runTimeoutTestAsync done
+
+ after () ->
+ finished = undefined
+
+ it 'should not finish before timeout occurs', () ->
+ expect(finished).to.be.false
+
+ # Errors thrown by Mocha show up in stdout; those by Abao in stderr.
+ it 'Mocha should throw an error', () ->
+ detail = "Error: Timeout of #{timeout}ms exceeded."
+ expect(stdout).to.have.string(detail)
+
+ it 'should run test but not complete', () ->
+ expect(stdout).to.have.string('1 failing')
+
+ it 'should exit due to error', () ->
+ expect(exitStatus).to.equal(1)
- it 'should not run test without hooks', () ->
- assert.include stdout, '0 passing'
describe 'when invoked with "--schema" option', () ->
- before (done) ->
- ramlFile = "#{RAML_DIR}/with-json-refs.raml"
- cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --schemas=#{SCHEMA_DIR}/*.json"
+
+ runSchemaTestAsync = (done) ->
+ pattern = "#{SCHEMA_DIR}/*.json"
+ ramlFile = "#{RAML_DIR}/machines-with_json_refs.raml"
+ cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --schemas=#{pattern}"
app = express()
app.get '/machines', (req, res) ->
- res.setHeader 'Content-Type', 'application/json'
machine =
type: 'bulldozer'
name: 'willy'
- response = [machine]
- res.status(200).send response
+ res.status(200).json([machine])
server = app.listen PORT, () ->
execCommand cmd, () ->
@@ -489,30 +779,37 @@ describe 'Command line interface', () ->
server.on 'close', done
- it 'exit status should be 0', () ->
- assert.equal exitStatus, 0
-
- describe 'when invoked with "--schema" option and expecting error', () ->
before (done) ->
- ramlFile = "#{RAML_DIR}/with-json-refs.raml"
- cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --schemas=#{SCHEMA_DIR}/*.json"
+ runSchemaTestAsync done
- app = express()
+ it 'should exit normally', () ->
+ expect(exitStatus).to.equal(0)
- app.get '/machines', (req, res) ->
- res.setHeader 'Content-Type', 'application/json'
- machine =
- typO: 'bulldozer'
- name: 'willy'
- response = [machine]
- res.status(200).send response
- server = app.listen PORT, () ->
- execCommand cmd, () ->
- server.close()
+ describe 'when expecting validation to fail', () ->
- server.on 'close', done
+ runSchemaFailTestAsync = (done) ->
+ pattern = "#{SCHEMA_DIR}/*.json"
+ ramlFile = "#{RAML_DIR}/machines-with_json_refs.raml"
+ cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --schemas=#{pattern}"
+
+ app = express()
+
+ app.get '/machines', (req, res) ->
+ machine =
+ typO: 'bulldozer' # 'type' != 'typO'
+ name: 'willy'
+ res.status(200).json([machine])
+
+ server = app.listen PORT, () ->
+ execCommand cmd, () ->
+ server.close()
+
+ server.on 'close', done
+
+ before (done) ->
+ runSchemaFailTestAsync done
- it 'exit status should be 1', () ->
- assert.equal exitStatus, 1
+ it 'should exit due to error', () ->
+ expect(exitStatus).to.equal(1)
diff --git a/test/fixtures/contacts.raml b/test/fixtures/contacts.raml
index 9231afa..bd796a4 100644
--- a/test/fixtures/contacts.raml
+++ b/test/fixtures/contacts.raml
@@ -6,6 +6,7 @@ version: v1
/contacts:
post:
+ description: Creates a new contact
body:
application/json:
schema: |
@@ -15,6 +16,10 @@ version: v1
{ "type": "Kulu", "name": "Mike" }
responses:
201:
+ headers:
+ location:
+ description: URI of the newly created contact
+ example: /contacts/{contact_id}
body:
application/json:
schema: |
@@ -22,11 +27,13 @@ version: v1
name: 'string'
example: |
{ "type": "Kulu", "name": "Mike" }
- /contacts/{id}
+ /contacts/{contact_id}
delete:
+ description: Deletes an existing contact by `contact_id`
responses:
204:
put:
+ description: Replaces an existing contact by `contact_id`
body:
application/json:
schema: |
@@ -44,6 +51,7 @@ version: v1
example: |
{ "type": "Kulu", "name": "Mike" }
get:
+ description: Gets an existing contact by `contact_id`
responses:
200:
body:
diff --git a/test/fixtures/1-get-1-post.raml b/test/fixtures/machines-1_get_1_post.raml
similarity index 77%
rename from test/fixtures/1-get-1-post.raml
rename to test/fixtures/machines-1_get_1_post.raml
index b656a52..d2d2e2b 100644
--- a/test/fixtures/1-get-1-post.raml
+++ b/test/fixtures/machines-1_get_1_post.raml
@@ -6,6 +6,7 @@ version: v1
/machines:
get:
+ description: Get a list of existing machines
responses:
200:
body:
@@ -18,6 +19,7 @@ version: v1
example: |
{ "type": "Kulu", "name": "Mike" }
post:
+ description: Creates a new machine
body:
application/json:
schema: |
@@ -27,6 +29,10 @@ version: v1
{ "type": "Kulu", "name": "Mike" }
responses:
201:
+ headers:
+ location:
+ description: URI of the newly created machine
+ example: /machines/{id}
body:
application/json:
schema: |
diff --git a/test/fixtures/machines-get_head_options.raml b/test/fixtures/machines-get_head_options.raml
new file mode 100644
index 0000000..0ee5c84
--- /dev/null
+++ b/test/fixtures/machines-get_head_options.raml
@@ -0,0 +1,59 @@
+#%RAML 0.8
+
+title: Machines API
+baseUri: http://localhost:3333
+
+/machines:
+ get:
+ description: Gets a list of existing machines
+ responses:
+ 200:
+ body:
+ application/json:
+ schema: |
+ [
+ type: 'string'
+ name: 'string'
+ ]
+ example: |
+ { "type": "Kulu", "name": "Mike" }
+
+ head:
+ description: Requests the headers that are returned from HTTP GET method
+ responses:
+ 200:
+ headers:
+ Content-Type:
+ description: Media type of response body
+ type: string
+ required: true
+ example: application/json; charset=utf-8
+ Content-Length:
+ description: Length of response body
+ type: string
+ required: true
+ example: 37
+ ETag:
+ description: Identifier for this version of the resource
+ type: string
+ required: true
+ example: W/"25-QoLpNeXVKDaodKGK5d2ua9ZMNAc"
+ body: null
+
+ options:
+ description: Describes the communication options for this resource.
+ responses:
+ 204:
+ headers:
+ Allow:
+ description: Which HTTP methods can be used with `machines`
+ type: string
+ required: true
+ example: OPTIONS, HEAD, GET
+ Cache-Control:
+ description: Defines caching policy for OPTIONS requests
+ type: string
+ required: true
+ example: no-cache, no-store, must-revalidate
+ body: null
+
diff --git a/test/fixtures/include_other_raml.raml b/test/fixtures/machines-include_other_raml.raml
similarity index 89%
rename from test/fixtures/include_other_raml.raml
rename to test/fixtures/machines-include_other_raml.raml
index 895add6..1141953 100644
--- a/test/fixtures/include_other_raml.raml
+++ b/test/fixtures/machines-include_other_raml.raml
@@ -9,6 +9,7 @@ securitySchemes:
/machines:
get:
+ description: Gets a list of existing machines
responses:
200:
body:
diff --git a/test/fixtures/inline_and_included_schemas.raml b/test/fixtures/machines-inline_and_included_schemas.raml
similarity index 91%
rename from test/fixtures/inline_and_included_schemas.raml
rename to test/fixtures/machines-inline_and_included_schemas.raml
index 0357800..e3ab190 100644
--- a/test/fixtures/inline_and_included_schemas.raml
+++ b/test/fixtures/machines-inline_and_included_schemas.raml
@@ -10,6 +10,7 @@ schemas:
/machines:
get:
+ description: Gets a list of existing machines
responses:
200:
body:
diff --git a/test/fixtures/no-method.raml b/test/fixtures/machines-no_method.raml
similarity index 88%
rename from test/fixtures/no-method.raml
rename to test/fixtures/machines-no_method.raml
index b9ae3a2..e145269 100644
--- a/test/fixtures/no-method.raml
+++ b/test/fixtures/machines-no_method.raml
@@ -7,6 +7,7 @@ version: v1
/root:
/machines:
get:
+ description: Gets a list of existing machines
responses:
200:
body:
diff --git a/test/fixtures/non_required_query_parameter.raml b/test/fixtures/machines-non_required_query_parameter.raml
similarity index 90%
rename from test/fixtures/non_required_query_parameter.raml
rename to test/fixtures/machines-non_required_query_parameter.raml
index 56264cf..5466f0b 100644
--- a/test/fixtures/non_required_query_parameter.raml
+++ b/test/fixtures/machines-non_required_query_parameter.raml
@@ -6,6 +6,7 @@ version: v1
/machines:
get:
+ description: Gets a list of existing machines
queryParameters:
quux:
type: string
diff --git a/test/fixtures/ref_other_schemas.raml b/test/fixtures/machines-ref_other_schemas.raml
similarity index 85%
rename from test/fixtures/ref_other_schemas.raml
rename to test/fixtures/machines-ref_other_schemas.raml
index 211e7df..728867c 100644
--- a/test/fixtures/ref_other_schemas.raml
+++ b/test/fixtures/machines-ref_other_schemas.raml
@@ -10,6 +10,7 @@ schemas:
/machines:
get:
+ description: Gets a list of existing machines
responses:
200:
body:
diff --git a/test/fixtures/required_query_parameter.raml b/test/fixtures/machines-required_query_parameter.raml
similarity index 90%
rename from test/fixtures/required_query_parameter.raml
rename to test/fixtures/machines-required_query_parameter.raml
index 0fb5a23..4e84652 100644
--- a/test/fixtures/required_query_parameter.raml
+++ b/test/fixtures/machines-required_query_parameter.raml
@@ -6,6 +6,7 @@ version: v1
/machines:
get:
+ description: Gets a list of existing machines
queryParameters:
quux:
type: string
diff --git a/test/fixtures/single-get.raml b/test/fixtures/machines-single_get.raml
similarity index 89%
rename from test/fixtures/single-get.raml
rename to test/fixtures/machines-single_get.raml
index f0e7316..6af46da 100644
--- a/test/fixtures/single-get.raml
+++ b/test/fixtures/machines-single_get.raml
@@ -5,6 +5,7 @@ baseUri: http://localhost:3333
/machines:
get:
+ description: Gets a list of existing machines
headers:
Abao-API-Key:
type: string
diff --git a/test/fixtures/three-levels.raml b/test/fixtures/machines-three_levels.raml
similarity index 80%
rename from test/fixtures/three-levels.raml
rename to test/fixtures/machines-three_levels.raml
index 9b03f99..30ec089 100644
--- a/test/fixtures/three-levels.raml
+++ b/test/fixtures/machines-three_levels.raml
@@ -6,6 +6,7 @@ version: v1
/machines:
get:
+ description: Gets a list of existing machines
responses:
200:
body:
@@ -23,10 +24,12 @@ version: v1
type: string
example: '1'
delete:
+ description: Delete a machine by `machine_id`
responses:
204:
/parts:
get:
+ description: Gets a list of machine `machine_id`'s parts
responses:
200:
body:
diff --git a/test/fixtures/with-json-refs.raml b/test/fixtures/machines-with_json_refs.raml
similarity index 100%
rename from test/fixtures/with-json-refs.raml
rename to test/fixtures/machines-with_json_refs.raml
index 640369a..cb1bbbb 100644
--- a/test/fixtures/with-json-refs.raml
+++ b/test/fixtures/machines-with_json_refs.raml
@@ -5,11 +5,11 @@ version: v1
resourceTypes:
- resource:
get:
+ description: Get <> by Identifier
headers:
Abao-API-Key:
type: string
example: abcdef
- description: Get <> by Identifier
responses:
200:
body:
diff --git a/test/fixtures/no-base-uri.raml b/test/fixtures/music-no_base_uri.raml
similarity index 83%
rename from test/fixtures/no-base-uri.raml
rename to test/fixtures/music-no_base_uri.raml
index 32aa268..cf7c133 100644
--- a/test/fixtures/no-base-uri.raml
+++ b/test/fixtures/music-no_base_uri.raml
@@ -11,12 +11,15 @@ traits:
/songs:
is: [ paged ]
get:
+ description: Gets a list of existing songs
queryParameters:
genre:
description: filter the songs by genre
post:
+ description: Adds a new song
/{songId}:
get:
+ description: Gets an existing song by `songId`
responses:
200:
body:
@@ -35,6 +38,5 @@ traits:
{ "title": "A Beautiful Day", "artist": "Mike" }
application/xml:
delete:
- description: |
- This method will *delete* an **individual song**
+ description: Deletes an existing song by `songId`
diff --git a/test/fixtures/simple.raml b/test/fixtures/music-simple.raml
similarity index 83%
rename from test/fixtures/simple.raml
rename to test/fixtures/music-simple.raml
index 4086a7e..d134fcc 100644
--- a/test/fixtures/simple.raml
+++ b/test/fixtures/music-simple.raml
@@ -12,12 +12,15 @@ traits:
/songs:
is: [ paged ]
get:
+ description: Gets a list of existing songs
queryParameters:
genre:
description: filter the songs by genre
post:
+ description: Adds a new song
/{songId}:
get:
+ description: Gets an existing song by `songId`
responses:
200:
body:
@@ -36,6 +39,5 @@ traits:
{ "title": "A Beautiful Day", "artist": "Mike" }
application/xml:
delete:
- description: |
- This method will *delete* an **individual song**
+ description: Deletes an existing song by `songId`
diff --git a/test/fixtures/vendor-content-type.raml b/test/fixtures/music-vendor_content_type.raml
similarity index 95%
rename from test/fixtures/vendor-content-type.raml
rename to test/fixtures/music-vendor_content_type.raml
index 199c17f..ce76a2e 100644
--- a/test/fixtures/vendor-content-type.raml
+++ b/test/fixtures/music-vendor_content_type.raml
@@ -9,6 +9,7 @@ version: v1
songId:
example: "mike-a-beautiful-day"
patch:
+ description: Edits an existing song by `songId`
body:
application/vnd.api+json:
schema: |
diff --git a/test/fixtures/test_hooks.coffee b/test/fixtures/test_hooks.coffee
index 10e4245..3ac38c6 100644
--- a/test/fixtures/test_hooks.coffee
+++ b/test/fixtures/test_hooks.coffee
@@ -1,5 +1,7 @@
{after} = require 'hooks'
-after "GET /machines -> 200", (test, done) ->
- console.error "after-hook-GET-machines"
+after 'GET /machines -> 200', (test, done) ->
+ 'use strict'
+ console.error 'after-hook-GET-machines'
done()
+
diff --git a/test/stub/server.coffee b/test/stub/server.coffee
index 9770482..da69919 100644
--- a/test/stub/server.coffee
+++ b/test/stub/server.coffee
@@ -1,18 +1,44 @@
-express = require 'express'
+###*
+# @file Express server stub
+#
+# Start:
+# $ ../../node_modules/coffee-script/bin/coffee server.coffee
+###
+require 'coffee-script/register'
-PORT = '3333'
+express = require 'express'
app = express()
+app.set 'port', process.env.PORT || 3333
+
+app.options '/machines', (req, res) ->
+ 'use strict'
+ allow = ['OPTIONS', 'HEAD', 'GET']
+ directives = ['no-cache', 'no-store', 'must-revalidate']
+ res.setHeader 'Allow', allow.join ','
+ res.setHeader 'Cache-Control', directives.join ','
+ res.setHeader 'Pragma', directives[0]
+ res.setHeader 'Expires', '0'
+ res.status(204).end()
app.get '/machines', (req, res) ->
- res.setHeader 'Content-Type', 'application/json'
+ 'use strict'
machine =
type: 'bulldozer'
name: 'willy'
- response = [machine]
- res.status(200).send response
+ res.status(200).json [machine]
+
+app.use (err, req, res, next) ->
+ 'use strict'
+ res.status(err.status || 500)
+ .json({
+ message: err.message,
+ stack: err.stack
+ })
+ return
-server = app.listen PORT, () ->
- console.log 'server started'
+server = app.listen app.get('port'), () ->
+ 'use strict'
+ console.log 'server listening on port', server.address().port
diff --git a/test/unit/abao-test.coffee b/test/unit/abao-test.coffee
index 0954f0e..69fb024 100644
--- a/test/unit/abao-test.coffee
+++ b/test/unit/abao-test.coffee
@@ -8,7 +8,6 @@ ramlParserStub = require 'raml-parser'
addTestsStub = require '../../lib/add-tests'
addHooksStub = require '../../lib/add-hooks'
runnerStub = require '../../lib/test-runner'
-applyConfigurationStub = require '../../lib/apply-configuration'
hooksStub = require '../../lib/hooks'
Abao = proxyquire '../../', {
@@ -16,7 +15,6 @@ Abao = proxyquire '../../', {
'./add-tests': addTestsStub,
'./add-hooks': addHooksStub,
'./test-runner': runnerStub,
- './apply-configuration': applyConfigurationStub,
'./hooks': hooksStub
}
@@ -25,6 +23,7 @@ chai.use(sinonChai)
describe 'Abao', () ->
+ 'use strict'
describe '#constructor', () ->
diff --git a/test/unit/add-hooks-test.coffee b/test/unit/add-hooks-test.coffee
index 9379a12..4c11f74 100644
--- a/test/unit/add-hooks-test.coffee
+++ b/test/unit/add-hooks-test.coffee
@@ -1,10 +1,15 @@
require 'coffee-errors'
-{assert} = require 'chai'
+chai = require 'chai'
+chai.use require('sinon-chai')
{EventEmitter} = require 'events'
+mute = require 'mute'
nock = require 'nock'
proxyquire = require 'proxyquire'
sinon = require 'sinon'
-mute = require 'mute'
+
+assert = chai.assert
+expect = chai.expect
+should = chai.should()
globStub = require 'glob'
pathStub = require 'path'
@@ -15,96 +20,175 @@ addHooks = proxyquire '../../lib/add-hooks', {
'path': pathStub
}
-describe 'addHooks(hooks, pattern)', () ->
+describe 'addHooks(hooks, pattern, callback)', () ->
+ 'use strict'
+ callback = undefined
+ globSyncSpy = undefined
+ addHookSpy = undefined
+ pathResolveSpy = undefined
+ consoleErrorSpy = undefined
transactions = {}
describe 'with no pattern', () ->
before () ->
- sinon.spy globStub, 'sync'
+ callback = sinon.spy()
+ globSyncSpy = sinon.spy globStub, 'sync'
- after () ->
- globStub.sync.restore()
+ it 'should return immediately', (done) ->
+ addHooks hooksStub, '', callback
+ globSyncSpy.should.not.have.been.called
+ done()
- it 'should return immediately', () ->
- addHooks(hooksStub, '')
- assert.ok globStub.sync.notCalled
+ it 'should return successful continuation', () ->
+ callback.should.have.been.calledOnce
+ callback.should.have.been.calledWith(
+ sinon.match.typeOf('null'))
- describe 'with valid pattern', () ->
+ after () ->
+ globStub.sync.restore()
- pattern = './test/**/*_hooks.*'
- it 'should return files', (done)->
- mute (unmute) ->
- sinon.spy globStub, 'sync'
- addHooks(hooksStub, pattern)
- assert.ok globStub.sync.called
- globStub.sync.restore()
+ describe 'with pattern', () ->
- unmute()
- done()
+ context 'not matching any files', () ->
- describe 'when files are valid js/coffeescript', () ->
+ pattern = '/path/to/directory/without/hooks/*'
beforeEach () ->
- sinon.spy globStub, 'sync'
- sinon.spy pathStub, 'resolve'
- sinon.spy hooksStub, 'addHook'
-
- afterEach () ->
- globStub.sync.restore()
- pathStub.resolve.restore()
- hooksStub.addHook.restore()
+ callback = sinon.spy()
+ addHookSpy = sinon.spy hooksStub, 'addHook'
+ globSyncSpy = sinon.stub globStub, 'sync'
+ .callsFake (pattern) ->
+ []
+ pathResolveSpy = sinon.spy pathStub, 'resolve'
- it 'should load the files', (done) ->
+ it 'should not return any file names', (done) ->
mute (unmute) ->
- addHooks(hooksStub, pattern)
- assert.ok pathStub.resolve.called
-
+ addHooks hooksStub, pattern, callback
+ globSyncSpy.should.have.returned []
unmute()
done()
- it 'should attach the hooks', (done) ->
+ it 'should not attempt to load files', (done) ->
mute (unmute) ->
- addHooks(hooksStub, pattern)
- assert.ok hooksStub.addHook.called
+ addHooks hooksStub, pattern, callback
+ pathResolveSpy.should.not.have.been.called
+ unmute()
+ done()
+ it 'should propagate the error condition', (done) ->
+ mute (unmute) ->
+ addHooks hooksStub, pattern, callback
+ callback.should.have.been.calledOnce
+ detail = "no hook files found matching pattern '#{pattern}'"
+ callback.should.have.been.calledWith(
+ sinon.match.instanceOf(Error).and(
+ sinon.match.has('message', detail)))
unmute()
done()
+ afterEach () ->
+ hooksStub.addHook.restore()
+ globStub.sync.restore()
+ pathStub.resolve.restore()
- describe 'when there is an error reading the hook files', () ->
- beforeEach () ->
- sinon.stub pathStub, 'resolve'
- .callsFake (path, rel) ->
- throw new Error()
- sinon.spy console, 'error'
- sinon.stub globStub, 'sync'
- .callsFake (pattern) ->
- ['invalid.xml', 'unexist.md']
- sinon.spy hooksStub, 'addHook'
+ context 'matching files', () ->
- afterEach () ->
- pathStub.resolve.restore()
- console.error.restore()
- globStub.sync.restore()
- hooksStub.addHook.restore()
+ pattern = './test/**/*_hooks.*'
- it 'should log a warning', (done) ->
+ it 'should return file names', (done) ->
mute (unmute) ->
- addHooks(hooksStub, pattern)
- assert.ok console.error.called
-
+ globSyncSpy = sinon.spy globStub, 'sync'
+ addHooks hooksStub, pattern, callback
+ globSyncSpy.should.have.been.called
+ globStub.sync.restore()
unmute()
done()
- it 'should not attach the hooks', (done) ->
- mute (unmute) ->
- addHooks(hooksStub, pattern)
- assert.ok hooksStub.addHook.notCalled
- unmute()
- done()
+ context 'when files are valid javascript/coffeescript', () ->
+
+ beforeEach () ->
+ callback = sinon.spy()
+ globSyncSpy = sinon.spy globStub, 'sync'
+ pathResolveSpy = sinon.spy pathStub, 'resolve'
+ addHookSpy = sinon.spy hooksStub, 'addHook'
+
+ it 'should load the files', (done) ->
+ mute (unmute) ->
+ addHooks hooksStub, pattern, callback
+ pathResolveSpy.should.have.been.called
+ unmute()
+ done()
+
+ it 'should attach the hooks', (done) ->
+ mute (unmute) ->
+ addHooks hooksStub, pattern, callback
+ addHookSpy.should.have.been.called
+ unmute()
+ done()
+
+ it 'should return successful continuation', (done) ->
+ mute (unmute) ->
+ addHooks hooksStub, pattern, callback
+ callback.should.have.been.calledOnce
+ callback.should.have.been.calledWith(
+ sinon.match.typeOf('null'))
+ unmute()
+ done()
+
+ afterEach () ->
+ globStub.sync.restore()
+ pathStub.resolve.restore()
+ hooksStub.addHook.restore()
+
+
+ context 'when error occurs reading the hook files', () ->
+
+ addHookSpy = undefined
+ consoleErrorSpy = undefined
+
+ beforeEach () ->
+ callback = sinon.spy()
+ pathResolveSpy = sinon.stub pathStub, 'resolve'
+ .callsFake (path, rel) ->
+ throw new Error 'resolve'
+ consoleErrorSpy = sinon.spy console, 'error'
+ globSyncSpy = sinon.stub globStub, 'sync'
+ .callsFake (pattern) ->
+ ['invalid.xml', 'unexist.md']
+ addHookSpy = sinon.spy hooksStub, 'addHook'
+
+ it 'should log an error', (done) ->
+ mute (unmute) ->
+ addHooks hooksStub, pattern, callback
+ consoleErrorSpy.should.have.been.called
+ unmute()
+ done()
+
+ it 'should not attach the hooks', (done) ->
+ mute (unmute) ->
+ addHooks hooksStub, pattern, callback
+ addHookSpy.should.not.have.been.called
+ unmute()
+ done()
+
+ it 'should propagate the error condition', (done) ->
+ mute (unmute) ->
+ addHooks hooksStub, pattern, callback
+ callback.should.have.been.calledOnce
+ callback.should.have.been.calledWith(
+ sinon.match.instanceOf(Error).and(
+ sinon.match.has('message', 'resolve')))
+ unmute()
+ done()
+
+ afterEach () ->
+ pathStub.resolve.restore()
+ console.error.restore()
+ globStub.sync.restore()
+ hooksStub.addHook.restore()
diff --git a/test/unit/add-tests-test.coffee b/test/unit/add-tests-test.coffee
index 00b32c1..878b85a 100644
--- a/test/unit/add-tests-test.coffee
+++ b/test/unit/add-tests-test.coffee
@@ -17,6 +17,7 @@ RAML_DIR = "#{FIXTURE_DIR}"
describe '#addTests', () ->
+ 'use strict'
describe '#run', () ->
@@ -24,17 +25,21 @@ describe '#addTests', () ->
tests = []
testFactory = new TestFactory()
- callback = ''
+ callback = undefined
before (done) ->
- ramlFile = "#{RAML_DIR}/single-get.raml"
+ ramlFile = "#{RAML_DIR}/machines-single_get.raml"
ramlParser.loadFile(ramlFile)
- .then (raml) ->
- callback = sinon.stub()
- callback.returns(done())
+ .then (raml) ->
+ callback = sinon.stub()
+ callback.returns(done())
- addTests raml, tests, hooks, callback, testFactory, false
+ addTests raml, tests, hooks, callback, testFactory, false
+ .catch (err) ->
+ console.error err
+ done(err)
return
+
after () ->
tests = []
@@ -68,23 +73,28 @@ describe '#addTests', () ->
assert.isNull res.headers
assert.isNull res.body
+
describe 'when endpoint has multiple methods', () ->
+
describe 'when processed in order specified in RAML', () ->
tests = []
testFactory = new TestFactory()
- callback = ''
+ callback = undefined
before (done) ->
-
- ramlFile = "#{RAML_DIR}/1-get-1-post.raml"
+ ramlFile = "#{RAML_DIR}/machines-1_get_1_post.raml"
ramlParser.loadFile(ramlFile)
- .then (raml) ->
- callback = sinon.stub()
- callback.returns(done())
-
- addTests raml, tests, hooks, callback, testFactory, false
+ .then (raml) ->
+ callback = sinon.stub()
+ callback.returns(done())
+
+ addTests raml, tests, hooks, callback, testFactory, false
+ .catch (err) ->
+ console.error err
+ done(err)
return
+
after () ->
tests = []
@@ -123,22 +133,26 @@ describe '#addTests', () ->
assert.isNull res.headers
assert.isNull res.body
+
describe 'when processed in order specified by "--sorted" option', () ->
tests = []
testFactory = new TestFactory()
- callback = ''
+ callback = undefined
before (done) ->
-
- ramlFile = "#{RAML_DIR}/1-get-1-post.raml"
+ ramlFile = "#{RAML_DIR}/machines-1_get_1_post.raml"
ramlParser.loadFile(ramlFile)
- .then (raml) ->
- callback = sinon.stub()
- callback.returns(done())
-
- addTests raml, tests, hooks, null, callback, testFactory, true
+ .then (raml) ->
+ callback = sinon.stub()
+ callback.returns(done())
+
+ addTests raml, tests, hooks, null, callback, testFactory, true
+ .catch (err) ->
+ console.error err
+ done(err)
return
+
after () ->
tests = []
@@ -177,22 +191,26 @@ describe '#addTests', () ->
assert.isNull res.headers
assert.isNull res.body
+
describe 'when RAML includes multiple referencing schemas', () ->
tests = []
- testFactory = new TestFactory
- callback = ''
+ testFactory = new TestFactory()
+ callback = undefined
before (done) ->
-
- ramlFile = "#{RAML_DIR}/ref_other_schemas.raml"
+ ramlFile = "#{RAML_DIR}/machines-ref_other_schemas.raml"
ramlParser.loadFile(ramlFile)
- .then (raml) ->
- callback = sinon.stub()
- callback.returns(done())
+ .then (raml) ->
+ callback = sinon.stub()
+ callback.returns(done())
- addTests raml, tests, hooks, callback, testFactory, false
+ addTests raml, tests, hooks, callback, testFactory, false
+ .catch (err) ->
+ console.error err
+ done(err)
return
+
after () ->
tests = []
@@ -218,26 +236,30 @@ describe '#addTests', () ->
res = tests[0].response
assert.equal res.status, 200
- assert.equal res.schema?.properties?.chick?.type, "string"
+ assert.equal res.schema?.properties?.chick?.type, 'string'
assert.isNull res.headers
assert.isNull res.body
+
describe 'when RAML has inline and included schemas', () ->
tests = []
- testFactory = new TestFactory
- callback = ''
+ testFactory = new TestFactory()
+ callback = undefined
before (done) ->
-
- ramlFile = "#{RAML_DIR}/inline_and_included_schemas.raml"
+ ramlFile = "#{RAML_DIR}/machines-inline_and_included_schemas.raml"
ramlParser.loadFile(ramlFile)
- .then (raml) ->
- callback = sinon.stub()
- callback.returns(done())
+ .then (raml) ->
+ callback = sinon.stub()
+ callback.returns(done())
- addTests raml, tests, hooks, callback, testFactory, false
+ addTests raml, tests, hooks, callback, testFactory, false
+ .catch (err) ->
+ console.error err
+ done(err)
return
+
after () ->
tests = []
@@ -263,25 +285,28 @@ describe '#addTests', () ->
res = tests[0].response
assert.equal res.status, 200
- assert.equal res.schema?.properties?.type["$ref"], "type2"
+ assert.equal res.schema?.properties?.type['$ref'], 'type2'
assert.isNull res.headers
assert.isNull res.body
+
describe 'when RAML contains three-levels endpoints', () ->
tests = []
testFactory = new TestFactory()
- callback = ''
+ callback = undefined
before (done) ->
-
- ramlFile = "#{RAML_DIR}/three-levels.raml"
+ ramlFile = "#{RAML_DIR}/machines-three_levels.raml"
ramlParser.loadFile(ramlFile)
- .then (raml) ->
- callback = sinon.stub()
- callback.returns(done())
+ .then (raml) ->
+ callback = sinon.stub()
+ callback.returns(done())
- addTests raml, tests, hooks, callback, testFactory, false
+ addTests raml, tests, hooks, callback, testFactory, false
+ .catch (err) ->
+ console.error err
+ done(err)
return
after () ->
@@ -308,21 +333,24 @@ describe '#addTests', () ->
assert.deepEqual test.request.params,
machine_id: '1'
+
describe 'when RAML has resource not defined method', () ->
tests = []
testFactory = new TestFactory()
- callback = ''
+ callback = undefined
before (done) ->
-
- ramlFile = "#{RAML_DIR}/no-method.raml"
+ ramlFile = "#{RAML_DIR}/machines-no_method.raml"
ramlParser.loadFile(ramlFile)
- .then (raml) ->
- callback = sinon.stub()
- callback.returns(done())
+ .then (raml) ->
+ callback = sinon.stub()
+ callback.returns(done())
- addTests raml, tests, hooks, callback, testFactory, false
+ addTests raml, tests, hooks, callback, testFactory, false
+ .catch (err) ->
+ console.error err
+ done(err)
return
after () ->
@@ -337,14 +365,14 @@ describe '#addTests', () ->
it 'should set test.name', () ->
assert.equal tests[0].name, 'GET /root/machines -> 200'
+
describe 'when RAML has invalid request body example', () ->
tests = []
testFactory = new TestFactory()
- callback = ''
+ callback = undefined
before (done) ->
-
raml = """
#%RAML 0.8
@@ -361,12 +389,15 @@ describe '#addTests', () ->
204:
"""
ramlParser.load(raml)
- .then (raml) ->
- callback = sinon.stub()
- callback.returns(done())
+ .then (raml) ->
+ callback = sinon.stub()
+ callback.returns(done())
- sinon.stub console, 'warn'
- addTests raml, tests, hooks, callback, testFactory, false
+ sinon.stub console, 'warn'
+ addTests raml, tests, hooks, callback, testFactory, false
+ .catch (err) ->
+ console.error err
+ done(err)
return
after () ->
@@ -383,20 +414,26 @@ describe '#addTests', () ->
assert.lengthOf tests, 1
assert.equal tests[0].name, 'POST /machines -> 204'
+
describe 'when RAML media type uses a JSON-suffixed vendor tree subtype', () ->
+
tests = []
testFactory = new TestFactory()
- callback = ''
+ callback = undefined
before (done) ->
- ramlFile = "#{RAML_DIR}/vendor-content-type.raml"
+ ramlFile = "#{RAML_DIR}/music-vendor_content_type.raml"
ramlParser.loadFile(ramlFile)
- .then (raml) ->
- callback = sinon.stub()
- callback.returns(done())
+ .then (raml) ->
+ callback = sinon.stub()
+ callback.returns(done())
- addTests raml, tests, hooks, callback, testFactory, false
+ addTests raml, tests, hooks, callback, testFactory, false
+ .catch (err) ->
+ console.error err
+ done(err)
return
+
after () ->
tests = []
@@ -430,41 +467,65 @@ describe '#addTests', () ->
describe 'when there is required query parameter with example value', () ->
+
tests = []
testFactory = new TestFactory()
- callback = ''
+ callback = undefined
before (done) ->
+ ramlFile = "#{RAML_DIR}/machines-required_query_parameter.raml"
+ ramlParser.loadFile(ramlFile)
+ .then (raml) ->
+ callback = sinon.stub()
+ callback.returns(done())
- ramlParser.loadFile("#{RAML_DIR}/required_query_parameter.raml")
- .then (raml) ->
- callback = sinon.stub()
- callback.returns(done())
-
- addTests raml, tests, hooks, callback, testFactory, false
+ addTests raml, tests, hooks, callback, testFactory, false
+ .catch (err) ->
+ console.error err
+ done(err)
return
after () ->
tests = []
+ it 'should run callback', () ->
+ assert.ok callback.called
+
+ it 'should add 1 test', () ->
+ assert.lengthOf tests, 1
+
it 'should append query parameters with example value', () ->
assert.equal tests[0].request.query['quux'], 'foo'
+
describe 'when there is no required query parameter', () ->
+
tests = []
testFactory = new TestFactory()
- callback = ''
+ callback = undefined
before (done) ->
- ramlParser.loadFile("#{RAML_DIR}/non_required_query_parameter.raml")
- .then (raml) ->
- callback = sinon.stub()
- callback.returns(done())
+ ramlFile = "#{RAML_DIR}/machines-non_required_query_parameter.raml"
+ ramlParser.loadFile(ramlFile)
+ .then (raml) ->
+ callback = sinon.stub()
+ callback.returns(done())
- addTests raml, tests, hooks, callback, testFactory, false
+ addTests raml, tests, hooks, callback, testFactory, false
+ .catch (err) ->
+ console.error err
+ done(err)
return
+
after () ->
tests = []
+ it 'should run callback', () ->
+ assert.ok callback.called
+
+ it 'should add 1 test', () ->
+ assert.lengthOf tests, 1
+
it 'should not append query parameters', () ->
assert.deepEqual tests[0].request.query, {}
+
diff --git a/test/unit/hooks-test.coffee b/test/unit/hooks-test.coffee
index 0988757..f23de6f 100644
--- a/test/unit/hooks-test.coffee
+++ b/test/unit/hooks-test.coffee
@@ -9,12 +9,15 @@ hooks = require '../../lib/hooks'
ABAO_IO_SERVER = 'http://abao.io'
describe 'Hooks', () ->
+ 'use strict'
+
+ noop = () -> {}
describe 'when adding before hook', () ->
before () ->
- hooks.before 'beforeHook', () ->
- ""
+ hooks.before 'beforeHook', noop
+
after () ->
hooks.beforeHooks = {}
@@ -25,8 +28,8 @@ describe 'Hooks', () ->
describe 'when adding after hook', () ->
before () ->
- hooks.after 'afterHook', () ->
- ""
+ hooks.after 'afterHook', noop
+
after () ->
hooks.afterHooks = {}
@@ -74,42 +77,42 @@ describe 'Hooks', () ->
hooks.beforeHooks = {}
it 'should add to hook list', () ->
- hooks.beforeEach () ->
+ hooks.beforeEach noop
assert.lengthOf hooks.beforeEachHooks, 1
it 'should invoke registered callbacks', (testDone) ->
before_called = false
before_each_called = false
- test_name = "before_test"
+ test_name = 'before_test'
hooks.before test_name, (test, done) ->
assert.equal test.name, test_name
before_called = true
assert.isTrue before_each_called,
- "before_hook should be called after before_each"
+ 'before_hook should be called after before_each'
done()
hooks.beforeEach (test, done) ->
assert.equal test.name, test_name
before_each_called = true
assert.isFalse before_called,
- "before_each should be called before before_hook"
+ 'before_each should be called before before_hook'
done()
hooks.runBefore {name: test_name}, () ->
- assert.isTrue before_each_called, "before_each should have been called"
- assert.isTrue before_called, "before_hook should have been called"
+ assert.isTrue before_each_called, 'before_each should have been called'
+ assert.isTrue before_called, 'before_hook should have been called'
testDone()
it 'should work without test-specific before', (testDone) ->
before_each_called = false
- test_name = "before_test"
+ test_name = 'before_test'
hooks.beforeEach (test, done) ->
assert.equal test.name, test_name
before_each_called = true
done()
hooks.runBefore {name: test_name}, () ->
- assert.isTrue before_each_called, "before_each should have been called"
+ assert.isTrue before_each_called, 'before_each should have been called'
testDone()
describe 'when adding afterEach hooks', () ->
@@ -119,42 +122,42 @@ describe 'Hooks', () ->
hooks.afterHooks = {}
it 'should add to hook list', () ->
- hooks.afterEach () ->
+ hooks.afterEach noop
assert.lengthOf hooks.afterEachHooks, 1
it 'should invoke registered callbacks', (testDone) ->
after_called = false
after_each_called = false
- test_name = "after_test"
+ test_name = 'after_test'
hooks.after test_name, (test, done) ->
assert.equal test.name, test_name
after_called = true
assert.isFalse after_each_called,
- "after_hook should be called before after_each"
+ 'after_hook should be called before after_each'
done()
hooks.afterEach (test, done) ->
assert.equal test.name, test_name
after_each_called = true
assert.isTrue after_called,
- "after_each should be called after after_hook"
+ 'after_each should be called after after_hook'
done()
hooks.runAfter {name: test_name}, () ->
- assert.isTrue after_each_called, "after_each should have been called"
- assert.isTrue after_called, "after_hook should have been called"
+ assert.isTrue after_each_called, 'after_each should have been called'
+ assert.isTrue after_called, 'after_hook should have been called'
testDone()
it 'should work without test-specific after', (testDone) ->
after_each_called = false
- test_name = "after_test"
+ test_name = 'after_test'
hooks.afterEach (test, done) ->
assert.equal test.name, test_name
after_each_called = true
done()
hooks.runAfter {name: test_name}, () ->
- assert.isTrue after_each_called, "after_each should have been called"
+ assert.isTrue after_each_called, 'after_each should have been called'
testDone()
describe 'when check has name', () ->
@@ -348,21 +351,21 @@ describe 'Hooks', () ->
afterEach () ->
hooks.contentTests = {}
- test_name = "content_test_test"
+ test_name = 'content_test_test'
it 'should get added to the set of hooks', () ->
- hooks.test(test_name, () ->)
- assert.isDefined(hooks.contentTests[test_name])
+ hooks.test test_name, noop
+ assert.isDefined hooks.contentTests[test_name]
describe 'adding two content tests fails', () ->
afterEach () ->
hooks.contentTests = {}
- test_name = "content_test_test"
+ test_name = 'content_test_test'
- it 'should assert when adding a second content test', () ->
+ it 'should assert when attempting to add a second content test', () ->
f = () ->
- hooks.test(test_name, () ->)
+ hooks.test test_name, noop
f()
assert.throw f,
"cannot have more than one test with the name: #{test_name}"
@@ -386,7 +389,7 @@ describe 'Hooks', () ->
afterEach () ->
hooks.skippedTests = []
- test_name = "content_test_test"
+ test_name = 'content_test_test'
it 'should get added to the set of hooks', () ->
hooks.skip test_name
diff --git a/test/unit/test-runner-test.coffee b/test/unit/test-runner-test.coffee
index fc60cb4..efc3d05 100644
--- a/test/unit/test-runner-test.coffee
+++ b/test/unit/test-runner-test.coffee
@@ -24,31 +24,38 @@ should = chai.should()
chai.use(sinonChai)
describe 'Test Runner', () ->
+ 'use strict'
runner = undefined
+ test = undefined
+
+ createStdTest = () ->
+ testname = 'GET /machines -> 200'
+ testFactory = new TestFactory()
+ stdTest = testFactory.create testname, undefined
+ stdTest.request.path = '/machines'
+ stdTest.request.method = 'GET'
+ return stdTest
+
describe '#run', () ->
describe 'when test is valid', () ->
- runner = ''
- beforeAllHook = ''
- afterAllHook = ''
- beforeHook = ''
- afterHook = ''
- runCallback = ''
- testFactory = new TestFactory()
- test = testFactory.create()
- test.name = 'GET /machines -> 200'
- test.request.path = '/machines'
- test.request.method = 'GET'
- test.response.status = 200
- test.response.schema = """[
- type: 'string'
- name: 'string'
- ]"""
+ beforeAllHook = undefined
+ afterAllHook = undefined
+ beforeHook = undefined
+ afterHook = undefined
+ runCallback = undefined
before (done) ->
+ test = createStdTest()
+ test.response.status = 200
+ test.response.schema = """[
+ type: 'string'
+ name: 'string'
+ ]"""
+
options =
server: "#{ABAO_IO_SERVER}"
@@ -117,7 +124,9 @@ describe 'Test Runner', () ->
hooksStub.runBefore.restore()
hooksStub.runAfter.restore()
- runCallback = ''
+ runCallback = undefined
+ runner = undefined
+ test = undefined
it 'should generate beforeAll hooks', () ->
mochaStub = runner.mocha
@@ -157,15 +166,8 @@ describe 'Test Runner', () ->
describe 'Interact with #test', () ->
- test = ''
- runner = ''
-
before (done) ->
- testFactory = new TestFactory()
- test = testFactory.create()
- test.name = 'GET /machines -> 200'
- test.request.path = '/machines'
- test.request.method = 'GET'
+ test = createStdTest()
test.response.status = 200
test.response.schema = """[
type: 'string'
@@ -188,6 +190,8 @@ describe 'Test Runner', () ->
after () ->
test.run.restore()
+ runner = undefined
+ test = undefined
it 'should call #test.run', () ->
assert.ok test.run.calledOnce
@@ -217,6 +221,8 @@ describe 'Test Runner', () ->
after () ->
runner.mocha.run.restore()
+ runner = undefined
+ test = undefined
it 'should run mocha', () ->
assert.ok runner.mocha.run.called
@@ -235,11 +241,7 @@ describe 'Test Runner', () ->
describe 'when test skipped in hooks', () ->
before (done) ->
- testFactory = new TestFactory()
- test = testFactory.create()
- test.name = 'GET /machines -> 200'
- test.request.path = '/machines'
- test.request.method = 'GET'
+ test = createStdTest()
test.response.status = 200
test.response.schema = """[
type: 'string'
@@ -262,6 +264,8 @@ describe 'Test Runner', () ->
after () ->
hooksStub.skippedTests = []
runner.mocha.run.restore()
+ runner = undefined
+ test = undefined
it 'should run mocha', () ->
assert.ok runner.mocha.run.called
@@ -280,11 +284,7 @@ describe 'Test Runner', () ->
describe 'when test has no response schema', () ->
before (done) ->
- testFactory = new TestFactory()
- test = testFactory.create()
- test.name = 'GET /machines -> 200'
- test.request.path = '/machines'
- test.request.method = 'GET'
+ test = createStdTest()
test.response.status = 200
options =
@@ -302,6 +302,8 @@ describe 'Test Runner', () ->
after () ->
runner.mocha.run.restore()
+ runner = undefined
+ test = undefined
it 'should run mocha', () ->
assert.ok runner.mocha.run.called
@@ -319,14 +321,10 @@ describe 'Test Runner', () ->
describe 'when test throws AssertionError', () ->
- afterAllHook = ''
+ afterAllHook = undefined
before (done) ->
- testFactory = new TestFactory()
- test = testFactory.create()
- test.name = 'GET /machines -> 200'
- test.request.path = '/machines'
- test.request.method = 'GET'
+ test = createStdTest()
test.response.status = 200
afterAllHook = sinon.stub()
@@ -349,7 +347,9 @@ describe 'Test Runner', () ->
done()
after () ->
- afterAllHook = ''
+ afterAllHook = undefined
+ runner = undefined
+ test = undefined
it 'should call afterAll hook', () ->
afterAllHook.should.have.been.called
@@ -357,15 +357,11 @@ describe 'Test Runner', () ->
describe 'when beforeAllHooks throws UncaughtError', () ->
- beforeAllHook = ''
- afterAllHook = ''
+ beforeAllHook = undefined
+ afterAllHook = undefined
before (done) ->
- testFactory = new TestFactory()
- test = testFactory.create()
- test.name = 'GET /machines -> 200'
- test.request.path = '/machines'
- test.request.method = 'GET'
+ test = createStdTest()
test.response.status = 200
beforeAllHook = sinon.stub()
@@ -391,8 +387,10 @@ describe 'Test Runner', () ->
done()
after () ->
- beforeAllHook = ''
- afterAllHook = ''
+ beforeAllHook = undefined
+ afterAllHook = undefined
+ runner = undefined
+ test = undefined
it 'should call afterAll hook', () ->
afterAllHook.should.have.been.called
@@ -403,11 +401,7 @@ describe 'Test Runner', () ->
describe 'list all tests with `names`', () ->
before (done) ->
- testFactory = new TestFactory()
- test = testFactory.create()
- test.name = 'GET /machines -> 200'
- test.request.path = '/machines'
- test.request.method = 'GET'
+ test = createStdTest()
test.response.status = 200
test.response.schema = """[
type: 'string'
@@ -430,8 +424,10 @@ describe 'Test Runner', () ->
done()
after () ->
- runner.mocha.run.restore()
console.log.restore()
+ runner.mocha.run.restore()
+ runner = undefined
+ test = undefined
it 'should not run mocha', () ->
assert.notOk runner.mocha.run.called
@@ -446,11 +442,7 @@ describe 'Test Runner', () ->
headers = undefined
before (done) ->
- testFactory = new TestFactory()
- test = testFactory.create()
- test.name = 'GET /machines -> 200'
- test.request.path = '/machines'
- test.request.method = 'GET'
+ test = createStdTest()
test.response.status = 200
test.response.schema = {}
@@ -465,13 +457,15 @@ describe 'Test Runner', () ->
runner = new TestRunner options, ''
sinon.stub runner.mocha, 'run'
.callsFake (callback) ->
- receivedTest = _.cloneDeep(test)
+ receivedTest = _.cloneDeep test
callback()
runner.run [test], hooksStub, done
after () ->
runner.mocha.run.restore()
+ runner = undefined
+ test = undefined
it 'should run mocha', () ->
assert.ok runner.mocha.run.called
@@ -482,17 +476,13 @@ describe 'Test Runner', () ->
describe 'run test with hooks only indicated by `hooks-only`', () ->
- testFactory = new TestFactory()
- test = testFactory.create()
- test.name = 'GET /machines -> 200'
- test.request.path = '/machines'
- test.request.method = 'GET'
- test.response.status = 200
- test.response.schema = {}
-
- suiteStub = ''
+ suiteStub = undefined
before (done) ->
+ test = createStdTest()
+ test.response.status = 200
+ test.response.schema = {}
+
options =
server: "#{SERVER}"
'hooks-only': true
@@ -519,11 +509,13 @@ describe 'Test Runner', () ->
runner.run [test], hooksStub, done
after () ->
- runner.mocha.run.restore()
- mocha.Suite.create.restore()
suiteStub.addTest.restore()
suiteStub.beforeAll.restore()
suiteStub.afterAll.restore()
+ mocha.Suite.create.restore()
+ runner.mocha.run.restore()
+ runner = undefined
+ test = undefined
it 'should run mocha', () ->
assert.ok runner.mocha.run.called
diff --git a/test/unit/test-test.coffee b/test/unit/test-test.coffee
index 59ba739..2f891f5 100644
--- a/test/unit/test-test.coffee
+++ b/test/unit/test-test.coffee
@@ -10,6 +10,7 @@ chai.use(sinonChai)
requestStub = sinon.stub()
requestStub.restore = () ->
+ 'use strict'
this.callsArgWith(1, null, {statusCode: 200}, '')
TestFactory = proxyquire '../../lib/test', {
@@ -20,6 +21,7 @@ ABAO_IO_SERVER = 'http://abao.io'
describe 'Test', () ->
+ 'use strict'
describe '#run', () ->
@@ -48,7 +50,12 @@ describe 'Test', () ->
test.request.body =
body: 'value'
test.response.status = 201
- test.response.schema = [{ type: 'object', properties: { type: 'string', name: 'string'}}]
+ test.response.schema = [
+ type: 'object'
+ properties:
+ type: 'string'
+ name: 'string'
+ ]
machine =
type: 'foo'
@@ -124,7 +131,12 @@ describe 'Test', () ->
test.request.body =
body: 'value'
test.response.status = 200
- test.response.schema = [{ type: 'object', properties: { type: 'string', name: 'string'}}]
+ test.response.schema = [
+ type: 'object'
+ properties:
+ type: 'string'
+ name: 'string'
+ ]
machine =
type: 'foo'
@@ -178,7 +190,6 @@ describe 'Test', () ->
)
tv4Stub = {}
- tv4Stub.banUnknown = false
tv4Stub.addSchema = sinon.spy()
TestTestFactory = proxyquire '../../lib/test', {
@@ -191,23 +202,20 @@ describe 'Test', () ->
new TestTestFactory('')
assert.isFalse globStub.sync.called
assert.isFalse fsStub.readFileSync.called
- assert.isFalse tv4Stub.banUnknown
assert.isFalse tv4Stub.addSchema.called
it 'test TestFactory with name 1', () ->
new TestTestFactory('thisisaword')
- assert.isTrue globStub.sync.calledWith('thisisaword')
+ assert.isTrue globStub.sync.calledWith 'thisisaword'
assert.isTrue fsStub.readFileSync.calledOnce
- assert.isTrue fsStub.readFileSync.calledWith('thisisaword','utf8')
- assert.isTrue tv4Stub.banUnknown
+ assert.isTrue fsStub.readFileSync.calledWith 'thisisaword', 'utf8'
assert.isTrue tv4Stub.addSchema.calledWith(JSON.parse('{ "text": "example" }'))
it 'test TestFactory with name 2', () ->
new TestTestFactory('thisIsAnotherWord')
- assert.isTrue globStub.sync.calledWith('thisIsAnotherWord')
+ assert.isTrue globStub.sync.calledWith 'thisIsAnotherWord'
assert.isTrue fsStub.readFileSync.calledTwice
- assert.isTrue fsStub.readFileSync.calledWith('thisIsAnotherWord','utf8')
- assert.isTrue tv4Stub.banUnknown
+ assert.isTrue fsStub.readFileSync.calledWith 'thisIsAnotherWord', 'utf8'
assert.isTrue tv4Stub.addSchema.calledWith(JSON.parse('{ "text": "example" }'))
@@ -261,7 +269,7 @@ describe 'Test', () ->
errorStub = null
responseStub =
- statusCode : 201
+ statusCode: 201
bodyStub = JSON.stringify
type: 'foo'
name: 'bar'
@@ -275,7 +283,7 @@ describe 'Test', () ->
errorStub = null
responseStub =
- statusCode : 201
+ statusCode: 201
bodyStub = null
fn = _.partial test.assertResponse, errorStub, responseStub, bodyStub
assert.throw fn, chai.AssertionError
@@ -286,7 +294,7 @@ describe 'Test', () ->
errorStub = null
responseStub =
- statusCode : 201
+ statusCode: 201
bodyStub = 'Im invalid'
fn = _.partial test.assertResponse, errorStub, responseStub, bodyStub
assert.throw fn, chai.AssertionError