From 6178e7bc43dda849985a4686534e0aab0511d16b Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Fri, 16 Mar 2018 00:16:59 -0500 Subject: [PATCH 01/64] build(coffeelint.json): Beef up error checking Using default values for all checks, enabled 15 additional checks. --- coffeelint.json | 128 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/coffeelint.json b/coffeelint.json index 362f039..97a2d5d 100644 --- a/coffeelint.json +++ b/coffeelint.json @@ -1,7 +1,135 @@ { + "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" } } From 17813958bc6e1d792bf1a2d96bf42a0a56e8ae54 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Fri, 16 Mar 2018 00:55:42 -0500 Subject: [PATCH 02/64] refactor(add-tests.coffee): Refactor checking for vendor tree media types Created function to check for compatible media types. Shortened line lengths when implemented. --- lib/add-tests.coffee | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/add-tests.coffee b/lib/add-tests.coffee index 47aa751..2bc5cee 100644 --- a/lib/add-tests.coffee +++ b/lib/add-tests.coffee @@ -16,6 +16,7 @@ parseSchema = (source) -> csonschema.parse source # @response.schema = csonschema.parse @response.schema + parseHeaders = (raml) -> headers = {} if raml @@ -23,6 +24,12 @@ parseHeaders = (raml) -> headers[key] = v.example headers + +getCompatibleMediaTypes = (bodyObj) -> + vendorRE = /^application\/(.*\+)?json/i + return (type for type of bodyObj when type.match(vendorRE)) + + addTests = (raml, tests, hooks, parent, callback, testFactory, sortFirst) -> # Handle 4th optional param @@ -120,10 +127,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 +146,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 From b5ceed714655c6032d0c7cefca664fdf69fe8955 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Fri, 16 Mar 2018 01:00:41 -0500 Subject: [PATCH 03/64] refactor(cli.coffee): Refactor to use string interpolation Refactored to use string interpolation in several places within `yargs` invocation. Shortened line lengths when implemented. Removed unneeded quotes from configuration object fields. --- lib/cli.coffee | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/cli.coffee b/lib/cli.coffee index 97dca65..93c34cc 100644 --- a/lib/cli.coffee +++ b/lib/cli.coffee @@ -38,11 +38,11 @@ mochaOptionNames = [ 'reporter', 'timeout' ] -binary = path.basename pkg.bin +prog = path.basename pkg.bin argv = yargs - .usage('Usage:\n ' + binary + ' [OPTIONS]' + - '\n\nExample:\n ' + binary + ' api.raml --server http://api.example.com') + .usage("Usage:\n #{prog} [OPTIONS]" + + "\n\nExample:\n #{prog} api.raml --server http://api.example.com") .options(Abao.options) .group(mochaOptionNames, 'Options passed to Mocha:') .implies('template', 'generate-hooks') @@ -53,24 +53,24 @@ argv = yargs # Ensure single positional argument present if argv._.length < 1 - throw new Error binary + ': must specify path to RAML file' + throw new Error "#{prog}: must specify path to RAML file" else if argv._.length > 1 - throw new Error binary + ': accepts single positional command-line argument' + throw new Error "#{prog}: 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) + .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...] + ramlPath: argv._[0], + options: _.omit argv, ['_', '$0', aliases...] mochaOptions = _.pick configuration.options, mochaOptionNames configuration.options = _.omit configuration.options, mochaOptionNames From 75231f129a0487d62bfa7932c678ebc59d6490a1 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Fri, 16 Mar 2018 01:16:42 -0500 Subject: [PATCH 04/64] style(hooks.coffee,test.coffee,test-runner.coffee): Fix CoffeeLint issue Increase to the number of required newlines after class definitions (3). --- lib/hooks.coffee | 1 + lib/test-runner.coffee | 1 + lib/test.coffee | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/hooks.coffee b/lib/hooks.coffee index 1ad696f..555ab16 100644 --- a/lib/hooks.coffee +++ b/lib/hooks.coffee @@ -80,5 +80,6 @@ class Hooks @skippedTests.indexOf(name) != -1 + module.exports = new Hooks() diff --git a/lib/test-runner.coffee b/lib/test-runner.coffee index b1f89fd..9938526 100644 --- a/lib/test-runner.coffee +++ b/lib/test-runner.coffee @@ -116,5 +116,6 @@ class TestRunner ], done + module.exports = TestRunner diff --git a/lib/test.coffee b/lib/test.coffee index 7b58a46..b34b4ed 100644 --- a/lib/test.coffee +++ b/lib/test.coffee @@ -33,6 +33,7 @@ class TestFactory return new Test(name, contentTest) + class Test constructor: (@name, @contentTest) -> @name ?= '' From bc4cd0efee0c7a5855c4646ecad708e8bdd19b56 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Fri, 16 Mar 2018 01:21:25 -0500 Subject: [PATCH 05/64] style(abao.coffee,generate-hooks.coffee): Correct CoffeeLint issues --- lib/abao.coffee | 3 ++- lib/generate-hooks.coffee | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/abao.coffee b/lib/abao.coffee index 2941f97..6bde043 100644 --- a/lib/abao.coffee +++ b/lib/abao.coffee @@ -2,7 +2,7 @@ # @file Abao class ### -sms = require("source-map-support").install({handleUncaughtExceptions: false}) +require('source-map-support').install({handleUncaughtExceptions: false}) ramlParser = require 'raml-parser' async = require 'async' @@ -55,6 +55,7 @@ class Abao ], done + module.exports = Abao module.exports.options = options diff --git a/lib/generate-hooks.coffee b/lib/generate-hooks.coffee index d16ca0a..f1c4835 100644 --- a/lib/generate-hooks.coffee +++ b/lib/generate-hooks.coffee @@ -19,7 +19,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 From 038d57a37561645cd2e8431c2a6d7f18b5a5eec3 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Fri, 16 Mar 2018 01:23:34 -0500 Subject: [PATCH 06/64] style(cli-test.coffee,test_hooks.coffee,add-hooks-test.coffee,add-tests-test.coffee,hooks-test.coffe --- test/e2e/cli-test.coffee | 4 ++-- test/fixtures/test_hooks.coffee | 4 ++-- test/unit/add-hooks-test.coffee | 2 +- test/unit/add-tests-test.coffee | 8 +++---- test/unit/hooks-test.coffee | 38 ++++++++++++++++----------------- test/unit/test-test.coffee | 24 +++++++++++++++------ 6 files changed, 45 insertions(+), 35 deletions(-) diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index e50cc2c..65b46ca 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -450,11 +450,11 @@ describe 'Command line interface', () -> t0 = '' app.get '/machines', (req, res) -> - t0 = new Date + t0 = new Date() server = app.listen PORT, () -> execCommand cmd, () -> - cost = new Date - t0 + cost = new Date() - t0 server.close() server.on 'close', done diff --git a/test/fixtures/test_hooks.coffee b/test/fixtures/test_hooks.coffee index 10e4245..40f3177 100644 --- a/test/fixtures/test_hooks.coffee +++ b/test/fixtures/test_hooks.coffee @@ -1,5 +1,5 @@ {after} = require 'hooks' -after "GET /machines -> 200", (test, done) -> - console.error "after-hook-GET-machines" +after 'GET /machines -> 200', (test, done) -> + console.error 'after-hook-GET-machines' done() diff --git a/test/unit/add-hooks-test.coffee b/test/unit/add-hooks-test.coffee index 9379a12..942957a 100644 --- a/test/unit/add-hooks-test.coffee +++ b/test/unit/add-hooks-test.coffee @@ -35,7 +35,7 @@ describe 'addHooks(hooks, pattern)', () -> pattern = './test/**/*_hooks.*' - it 'should return files', (done)-> + it 'should return files', (done) -> mute (unmute) -> sinon.spy globStub, 'sync' addHooks(hooksStub, pattern) diff --git a/test/unit/add-tests-test.coffee b/test/unit/add-tests-test.coffee index 00b32c1..169aa9f 100644 --- a/test/unit/add-tests-test.coffee +++ b/test/unit/add-tests-test.coffee @@ -180,7 +180,7 @@ describe '#addTests', () -> describe 'when RAML includes multiple referencing schemas', () -> tests = [] - testFactory = new TestFactory + testFactory = new TestFactory() callback = '' before (done) -> @@ -218,14 +218,14 @@ 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 + testFactory = new TestFactory() callback = '' before (done) -> @@ -263,7 +263,7 @@ 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 diff --git a/test/unit/hooks-test.coffee b/test/unit/hooks-test.coffee index 0988757..9854aad 100644 --- a/test/unit/hooks-test.coffee +++ b/test/unit/hooks-test.coffee @@ -14,7 +14,7 @@ describe 'Hooks', () -> before () -> hooks.before 'beforeHook', () -> - "" + '' after () -> hooks.beforeHooks = {} @@ -26,7 +26,7 @@ describe 'Hooks', () -> before () -> hooks.after 'afterHook', () -> - "" + '' after () -> hooks.afterHooks = {} @@ -80,36 +80,36 @@ describe 'Hooks', () -> 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', () -> @@ -125,36 +125,36 @@ describe 'Hooks', () -> 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,7 +348,7 @@ 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, () ->) @@ -358,7 +358,7 @@ describe 'Hooks', () -> afterEach () -> hooks.contentTests = {} - test_name = "content_test_test" + test_name = 'content_test_test' it 'should assert when adding a second content test', () -> f = () -> @@ -386,7 +386,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-test.coffee b/test/unit/test-test.coffee index 59ba739..32cada3 100644 --- a/test/unit/test-test.coffee +++ b/test/unit/test-test.coffee @@ -48,7 +48,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 +129,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' @@ -198,7 +208,7 @@ describe 'Test', () -> new TestTestFactory('thisisaword') assert.isTrue globStub.sync.calledWith('thisisaword') assert.isTrue fsStub.readFileSync.calledOnce - assert.isTrue fsStub.readFileSync.calledWith('thisisaword','utf8') + assert.isTrue fsStub.readFileSync.calledWith 'thisisaword', 'utf8' assert.isTrue tv4Stub.banUnknown assert.isTrue tv4Stub.addSchema.calledWith(JSON.parse('{ "text": "example" }')) @@ -206,7 +216,7 @@ describe 'Test', () -> new TestTestFactory('thisIsAnotherWord') assert.isTrue globStub.sync.calledWith('thisIsAnotherWord') assert.isTrue fsStub.readFileSync.calledTwice - assert.isTrue fsStub.readFileSync.calledWith('thisIsAnotherWord','utf8') + assert.isTrue fsStub.readFileSync.calledWith 'thisIsAnotherWord', 'utf8' assert.isTrue tv4Stub.banUnknown assert.isTrue tv4Stub.addSchema.calledWith(JSON.parse('{ "text": "example" }')) @@ -261,7 +271,7 @@ describe 'Test', () -> errorStub = null responseStub = - statusCode : 201 + statusCode: 201 bodyStub = JSON.stringify type: 'foo' name: 'bar' @@ -275,7 +285,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 +296,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 From 3e7d2cdc9529b8c5579df93f2a417731be35b8d8 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Fri, 16 Mar 2018 01:32:37 -0500 Subject: [PATCH 07/64] style(test-test.coffee): Remove unnecessary parentheses --- test/unit/test-test.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/test-test.coffee b/test/unit/test-test.coffee index 32cada3..a0ab922 100644 --- a/test/unit/test-test.coffee +++ b/test/unit/test-test.coffee @@ -206,7 +206,7 @@ describe 'Test', () -> 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 @@ -214,7 +214,7 @@ describe 'Test', () -> 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 From c47a47035d66e108727c6dab45dd283b07cc2c3c Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Fri, 16 Mar 2018 01:57:44 -0500 Subject: [PATCH 08/64] style(lib/*.coffee): Reorder required modules --- lib/abao.coffee | 8 ++++---- lib/add-hooks.coffee | 2 +- lib/add-tests.coffee | 2 +- lib/cli.coffee | 1 + lib/test-runner.coffee | 3 ++- lib/test.coffee | 8 ++++---- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/abao.coffee b/lib/abao.coffee index 6bde043..cfc2250 100644 --- a/lib/abao.coffee +++ b/lib/abao.coffee @@ -3,16 +3,16 @@ ### require('source-map-support').install({handleUncaughtExceptions: false}) -ramlParser = require 'raml-parser' 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' hooks = require './hooks' +options = require './options' +Runner = require './test-runner' +TestFactory = require './test' class Abao diff --git a/lib/add-hooks.coffee b/lib/add-hooks.coffee index 247c1ad..18d0825 100644 --- a/lib/add-hooks.coffee +++ b/lib/add-hooks.coffee @@ -3,9 +3,9 @@ ### require 'coffee-script/register' -proxyquire = require('proxyquire').noCallThru() glob = require 'glob' path = require 'path' +proxyquire = require('proxyquire').noCallThru() addHooks = (hooks, pattern) -> diff --git a/lib/add-tests.coffee b/lib/add-tests.coffee index 2bc5cee..27f7c7b 100644 --- a/lib/add-tests.coffee +++ b/lib/add-tests.coffee @@ -3,8 +3,8 @@ ### async = require 'async' -_ = require 'lodash' csonschema = require 'csonschema' +_ = require 'lodash' parseSchema = (source) -> diff --git a/lib/cli.coffee b/lib/cli.coffee index 93c34cc..3544661 100644 --- a/lib/cli.coffee +++ b/lib/cli.coffee @@ -7,6 +7,7 @@ require 'coffee-script/register' path = require 'path' _ = require 'lodash' yargs = require 'yargs' + Abao = require '../lib/abao' pkg = require '../package' diff --git a/lib/test-runner.coffee b/lib/test-runner.coffee index 9938526..34e0fb3 100644 --- a/lib/test-runner.coffee +++ b/lib/test-runner.coffee @@ -2,11 +2,12 @@ # @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' diff --git a/lib/test.coffee b/lib/test.coffee index b34b4ed..67ec72f 100644 --- a/lib/test.coffee +++ b/lib/test.coffee @@ -2,13 +2,13 @@ # @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 From b416e6c27efa4a8ba9317ded034ddfb6362fe60c Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Fri, 16 Mar 2018 02:40:06 -0500 Subject: [PATCH 09/64] style(Add whitespace): Added whitespace between test areas. --- test/e2e/cli-test.coffee | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index 65b46ca..03bc229 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -45,6 +45,7 @@ execCommand = (cmd, callback) -> exitStatus = code if exitStatus == null and code != undefined callback() + describe 'Command line interface', () -> describe 'when run without any arguments', (done) -> @@ -87,6 +88,7 @@ describe 'Command line interface', () -> describe 'when RAML argument unnecessary', () -> describe 'when invoked with "--reporters" option', () -> + reporters = '' before (done) -> @@ -102,6 +104,7 @@ describe 'Command line interface', () -> describe 'when invoked with "--version" option', () -> + before (done) -> cmd = "#{ABAO_BIN} --version" @@ -115,6 +118,7 @@ describe 'Command line interface', () -> describe 'when invoked with "--help" option', () -> + before (done) -> cmd = "#{ABAO_BIN} --help" @@ -126,9 +130,11 @@ describe 'Command line interface', () -> it 'should print usage to stdout', () -> assert.equal stdout.split('\n')[0], 'Usage:' + describe 'when RAML argument required', () -> describe 'when invoked with "--names" option', () -> + before (done) -> ramlFile = "#{RAML_DIR}/single-get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --names" @@ -146,7 +152,9 @@ describe 'Command line interface', () -> describe 'when invoked with "--generate-hooks" option', () -> + describe 'by itself', () -> + before (done) -> ramlFile = "#{RAML_DIR}/single-get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --generate-hooks" @@ -164,6 +172,7 @@ describe 'Command line interface', () -> describe 'with "--template" option', () -> + before (done) -> templateFile = "#{TEMPLATE_DIR}/hookfile.js" ramlFile = "#{RAML_DIR}/single-get.raml" @@ -180,7 +189,9 @@ describe 'Command line interface', () -> it 'should not run tests', () -> assert.notInclude stdout, '0 passing' + describe 'when invoked with "--template" but without "--generate-hooks" option', () -> + before (done) -> templateFile = "#{TEMPLATE_DIR}/hookfile.js" ramlFile = "#{RAML_DIR}/single-get.raml" @@ -197,6 +208,7 @@ describe 'Command line interface', () -> describe 'when RAML file not found', (done) -> + before (done) -> ramlFile = "#{RAML_DIR}/nonexistent_path.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER}" @@ -213,8 +225,11 @@ describe 'Command line interface', () -> 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" cmd = "#{ABAO_BIN} #{ramlFile} --reporter json" @@ -227,6 +242,7 @@ describe 'Command line interface', () -> it 'should print error message to stderr', () -> assert.include stderr, 'no API endpoint specified' + describe 'when RAML file does specify "baseUri"', () -> before (done) -> @@ -259,7 +275,9 @@ describe 'Command line interface', () -> 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 the server is responding as specified in the RAML', () -> + before (done) -> ramlFile = "#{RAML_DIR}/single-get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --reporter json" @@ -290,7 +308,9 @@ describe 'Command line interface', () -> 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" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER}" @@ -317,9 +337,11 @@ describe 'Command line interface', () -> 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" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --reporter spec" @@ -343,6 +365,7 @@ describe 'Command line interface', () -> it 'should print using the specified reporter', () -> assert.include stdout, '1 passing' + describe 'when invoked with "--header" option', () -> receivedRequest = {} @@ -413,6 +436,7 @@ describe 'Command line interface', () -> describe 'when invoked with "--hooks-only" option', () -> + before (done) -> ramlFile = "#{RAML_DIR}/single-get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --hooks-only" @@ -439,7 +463,9 @@ describe 'Command line interface', () -> it 'should not run test without hooks', () -> assert.include stdout, '1 pending' + describe 'when invoked with "--timeout" option', () -> + cost = '' before (done) -> @@ -468,7 +494,9 @@ describe 'Command line interface', () -> 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" @@ -492,7 +520,9 @@ describe 'Command line interface', () -> 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" From 6fb2314d689132cdef8d6dd7ff35b9dfaf668e01 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Sat, 17 Mar 2018 21:12:55 -0500 Subject: [PATCH 10/64] test(cli-test.coffee): Rework E2E Test Added ability to dump individual test results. Each test now in function invoked from `before()` method. Converted tests to use `expect()`. Reworded some test descriptions. Changed Express app response method to `.json()` shortening each test by two lines. Replaced existing "--timeout" test as it didn't actually check whether Mocha stopped the test due to timeout occurring. --- test/e2e/cli-test.coffee | 430 +++++++++++++++++++++++++-------------- 1 file changed, 282 insertions(+), 148 deletions(-) diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index 03bc229..8368912 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,6 +21,14 @@ CMD_PREFIX = '' ABAO_BIN = './bin/abao' MOCHA_BIN = './node_modules/mocha/bin/mocha' +mochaJsonReportKeys = [ + 'stats', + 'tests', + 'pending', + 'failures', + 'passes' +] + stderr = '' stdout = '' report = '' @@ -26,23 +36,46 @@ 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) -> 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() @@ -50,37 +83,45 @@ describe 'Command line interface', () -> 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) -> + runTooManyArgTestAsync = (done) -> ramlFile = "#{RAML_DIR}/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) -> @@ -91,137 +132,162 @@ describe 'Command line interface', () -> 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) -> + runNamesTestAsync = (done) -> ramlFile = "#{RAML_DIR}/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) -> + runGenHooksTestAsync = (done) -> ramlFile = "#{RAML_DIR}/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" 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" 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', () -> @@ -230,34 +296,37 @@ describe 'Command line interface', () -> describe 'when RAML file does not specify "baseUri"', () -> - before (done) -> + runUnspecifiedServerTestAsync = (done) -> ramlFile = "#{RAML_DIR}/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') + it 'should exit due to error', () -> + expect(exitStatus).to.equal(1) - describe 'when RAML file does specify "baseUri"', () -> - before (done) -> + describe 'when RAML file specifies "baseUri"', () -> + + resTestTitle = 'GET /machines -> 200 Validate response code and body' + + runBaseUriServerTestAsync = (done) -> ramlFile = "#{RAML_DIR}/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, () -> @@ -265,32 +334,38 @@ 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) -> + resTestTitle = 'GET /machines -> 200 Validate response code and body' + + runNormalTestAsync = (done) -> ramlFile = "#{RAML_DIR}/single-get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --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, () -> @@ -298,32 +373,36 @@ describe 'Command line interface', () -> server.on 'close', done - it 'exit status should be 0', () -> - assert.equal exitStatus, 0 + before (done) -> + runNormalTestAsync 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 RAML includes other RAML files', () -> - before (done) -> + runRamlIncludesTestAsync = (done) -> ramlFile = "#{RAML_DIR}/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, () -> @@ -331,30 +410,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 tests run', () -> - assert.include stdout, '1 passing' + expect(stdout).to.have.string('1 passing') + + it 'should exit normally', () -> + expect(exitStatus).to.equal(0) describe 'when called with arguments', () -> describe 'when invoked with "--reporter" option', () -> - before (done) -> + runReporterTestAsync = (done) -> ramlFile = "#{RAML_DIR}/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, () -> @@ -362,28 +442,33 @@ 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 = {} - before (done) -> + runHeaderTestAsync = (done) -> + extraHeader = 'Accept:application/json' ramlFile = "#{RAML_DIR}/single-get.raml" - cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --header Accept:application/json" + cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --header #{extraHeader}" app = express() 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 + res.status(200).json([machine]) server = app.listen PORT, () -> execCommand cmd, () -> @@ -391,34 +476,36 @@ describe 'Command line interface', () -> server.on 'close', done - it 'should have an additional header in the request', () -> - assert.equal receivedRequest.headers.accept, 'application/json' + before (done) -> + runHeaderTestAsync done - it 'exit status should be 0', () -> - assert.equal exitStatus, 0 + it 'should have an additional header in the request', () -> + expect(receivedRequest.headers.accept).to.equal('application/json') it 'should print count of tests run', () -> - 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 "--hookfiles" option', () -> receivedRequest = {} - before (done) -> + runHookfilesTestAsync = (done) -> + pattern = "#{HOOK_DIR}/*_hooks.*" ramlFile = "#{RAML_DIR}/single-get.raml" - cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --hookfiles=#{HOOK_DIR}/*_hooks.*" + cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --hookfiles=#{pattern}" app = express() 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 + res.status(200).json([machine]) server = app.listen PORT, () -> execCommand cmd, () -> @@ -426,30 +513,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) -> + runHooksOnlyTestAsync = (done) -> ramlFile = "#{RAML_DIR}/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, () -> @@ -457,59 +548,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 = '' + timeout = undefined + elapsed = -1 + finished = undefined - before (done) -> + runTimeoutTestAsync = (done) -> ramlFile = "#{RAML_DIR}/single-get.raml" - cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --timeout 100" + 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', () -> - it 'should not run test without hooks', () -> - assert.include stdout, '0 passing' + 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) describe 'when invoked with "--schema" option', () -> - before (done) -> + runSchemaTestAsync = (done) -> + pattern = "#{SCHEMA_DIR}/*.json" ramlFile = "#{RAML_DIR}/with-json-refs.raml" - cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --schemas=#{SCHEMA_DIR}/*.json" + 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, () -> @@ -517,32 +646,37 @@ describe 'Command line interface', () -> server.on 'close', done - it 'exit status should be 0', () -> - assert.equal exitStatus, 0 + before (done) -> + runSchemaTestAsync done + it 'should exit normally', () -> + expect(exitStatus).to.equal(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" + describe 'when expecting error', () -> - app = express() + runSchemaFailTestAsync = (done) -> + pattern = "#{SCHEMA_DIR}/*.json" + ramlFile = "#{RAML_DIR}/with-json-refs.raml" + cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --schemas=#{pattern}" - app.get '/machines', (req, res) -> - res.setHeader 'Content-Type', 'application/json' - machine = - typO: 'bulldozer' - name: 'willy' - response = [machine] - res.status(200).send response + app = express() - server = app.listen PORT, () -> - execCommand cmd, () -> - server.close() + app.get '/machines', (req, res) -> + machine = + typO: 'bulldozer' # 'type' != 'typ0' + name: 'willy' + res.status(200).json([machine]) - server.on 'close', done + 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) From c2453e76b3ac7158b70dbf802cb6390aa0b6e855 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 19 Mar 2018 10:51:10 -0500 Subject: [PATCH 11/64] build(Gruntfile.coffee,package.json): Enable linting of documentation Added `markdownlint` and configured it as a Grunt task. --- Gruntfile.coffee | 16 ++++++++++++++-- package.json | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Gruntfile.coffee b/Gruntfile.coffee index d53dbf5..6b91cfe 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -10,6 +10,7 @@ module.exports = (grunt) -> # Load in the module information pkg: grunt.file.readJSON 'package.json' + readme: 'README.md' gruntfile: 'Gruntfile.coffee' clean: @@ -42,6 +43,8 @@ module.exports = (grunt) -> ] coffeelint: + options: + configFile: 'coffeelint.json' default: src: [ 'lib/*.coffee' @@ -49,8 +52,14 @@ module.exports = (grunt) -> ] gruntfile: src: '<%= gruntfile %>' + + markdownlint: options: - configFile: 'coffeelint.json' + config: require './.markdownlint.json' + default: + src: [ + '<%= readme %>' + ] coffeecov: transpile: @@ -84,7 +93,10 @@ module.exports = (grunt) -> ] grunt.registerTask 'instrument', [ 'coffeecov' ] - grunt.registerTask 'lint', [ 'coffeelint' ] + grunt.registerTask 'lint', [ + 'coffeelint', + 'markdownlint' + ] grunt.registerTask 'test', [ 'lint' diff --git a/package.json b/package.json index d389dba..ad8598e 100644 --- a/package.json +++ b/package.json @@ -72,9 +72,11 @@ "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", "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", From c57545030b8ef6c6461a4572ab22dca429cbf773 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 19 Mar 2018 10:55:16 -0500 Subject: [PATCH 12/64] build(.markdownlint.json): Enable linting of documentation Whoops. Forgot to add markdownlint config file with last commit. --- .markdownlint.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .markdownlint.json 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 + } +} From 3fbef674c6786e7bc3349be8858e3beb42a6ca63 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 19 Mar 2018 11:41:53 -0500 Subject: [PATCH 13/64] build(Gruntfile.coffee): Fix indentation of Grunttask init --- Gruntfile.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gruntfile.coffee b/Gruntfile.coffee index 6b91cfe..8626a50 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -55,7 +55,7 @@ module.exports = (grunt) -> markdownlint: options: - config: require './.markdownlint.json' + config: require './.markdownlint.json' default: src: [ '<%= readme %>' From 3b62cdd658b7a91038912040067ac35b934625d3 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 19 Mar 2018 11:50:03 -0500 Subject: [PATCH 14/64] docs(README.md): Fix markdown lint errors --- README.md | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index cdfd9af..ac9cff1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -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] @@ -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 @@ -208,24 +208,26 @@ 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 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: `{}`]. ### 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] @@ -298,4 +300,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 - From bc97621eda6d89798f4a8e2febd15689bdff7408 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 19 Mar 2018 14:12:43 -0500 Subject: [PATCH 15/64] docs(README.md): Minor rewording --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ac9cff1..42633d4 100644 --- a/README.md +++ b/README.md @@ -208,12 +208,13 @@ test 'GET /machines -> 200', (response, body, done) -> ### test.request -* `server` - Server address, provided from command line. +* `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: `{}`]. +* `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: `{}`]. From b65170a74f51cce98a9b8f572244194d123ccb14 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 19 Mar 2018 14:14:50 -0500 Subject: [PATCH 16/64] docs(README.md): Renamed xref --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 42633d4..2d2110f 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ 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] @@ -288,10 +288,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/ From d04b680032a8038a43939a476729f08cdfa4df12 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 21 Mar 2018 10:41:13 -0500 Subject: [PATCH 17/64] build(coffeelint.json,package.json): Check for 'use strict' Added package that checks for 'use strict' within CoffeeScript source. Configured coffeelint to add the rule. --- coffeelint.json | 6 ++++++ package.json | 1 + 2 files changed, 7 insertions(+) diff --git a/coffeelint.json b/coffeelint.json index 97a2d5d..ad370e2 100644 --- a/coffeelint.json +++ b/coffeelint.json @@ -131,5 +131,11 @@ }, "transform_messes_up_line_numbers": { "level": "warn" + }, + "use_strict": { + "module": "coffeelint-use-strict", + "level": "warn", + "allowGlobal": false, + "requireGlobal": false } } diff --git a/package.json b/package.json index ad8598e..fb2318a 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "yargs": "^11.1.0" }, "devDependencies": { + "coffeelint-use-strict": "^1.0.0", "coveralls": "^2.11.14", "cz-conventional-changelog": "^2.1.0", "express": "^4.12.0", From c86346663fa6f2e846cc934e2138d76587d97918 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 21 Mar 2018 10:54:25 -0500 Subject: [PATCH 18/64] refactor(*.coffee): Enable 'use strict' checking Added 'use strict' to (almost) all functions within codebase. Couple warnings remain. CLI coming refactor will eliminate two more. --- Gruntfile.coffee | 1 + lib/abao.coffee | 2 ++ lib/add-hooks.coffee | 2 +- lib/add-tests.coffee | 4 ++++ lib/apply-configuration.coffee | 1 + lib/cli.coffee | 3 +++ lib/generate-hooks.coffee | 1 + lib/hooks.coffee | 16 ++++++++++++++++ lib/test-runner.coffee | 3 +++ lib/test.coffee | 7 +++++++ test/e2e/cli-test.coffee | 2 ++ test/unit/abao-test.coffee | 1 + test/unit/add-hooks-test.coffee | 1 + test/unit/add-tests-test.coffee | 1 + test/unit/hooks-test.coffee | 1 + test/unit/test-runner-test.coffee | 1 + test/unit/test-test.coffee | 2 ++ 17 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Gruntfile.coffee b/Gruntfile.coffee index 8626a50..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 diff --git a/lib/abao.coffee b/lib/abao.coffee index cfc2250..ff746c0 100644 --- a/lib/abao.coffee +++ b/lib/abao.coffee @@ -17,11 +17,13 @@ TestFactory = require './test' class Abao constructor: (config) -> + 'use strict' @configuration = applyConfiguration(config) @tests = [] @hooks = hooks run: (done) -> + 'use strict' config = @configuration tests = @tests hooks = @hooks diff --git a/lib/add-hooks.coffee b/lib/add-hooks.coffee index 18d0825..25c7efe 100644 --- a/lib/add-hooks.coffee +++ b/lib/add-hooks.coffee @@ -9,7 +9,7 @@ proxyquire = require('proxyquire').noCallThru() addHooks = (hooks, pattern) -> - + 'use strict' if pattern files = glob.sync pattern diff --git a/lib/add-tests.coffee b/lib/add-tests.coffee index 27f7c7b..460578e 100644 --- a/lib/add-tests.coffee +++ b/lib/add-tests.coffee @@ -8,6 +8,7 @@ _ = require 'lodash' parseSchema = (source) -> + 'use strict' if source.contains('$schema') #jsonschema # @response.schema = JSON.parse @response.schema @@ -18,6 +19,7 @@ parseSchema = (source) -> parseHeaders = (raml) -> + 'use strict' headers = {} if raml for key, v of raml @@ -26,11 +28,13 @@ parseHeaders = (raml) -> 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) diff --git a/lib/apply-configuration.coffee b/lib/apply-configuration.coffee index 2bbd129..1e8082b 100644 --- a/lib/apply-configuration.coffee +++ b/lib/apply-configuration.coffee @@ -3,6 +3,7 @@ ### applyConfiguration = (config) -> + 'use strict' coerceToArray = (value) -> if typeof value is 'string' diff --git a/lib/cli.coffee b/lib/cli.coffee index 3544661..61cb18c 100644 --- a/lib/cli.coffee +++ b/lib/cli.coffee @@ -15,6 +15,7 @@ EXIT_SUCCESS = 0 EXIT_FAILURE = 1 showReporters = () -> + 'use strict' # Copied from node_modules/mocha/_mocha console.log() console.log ' dot - dot matrix' @@ -48,6 +49,7 @@ argv = yargs .group(mochaOptionNames, 'Options passed to Mocha:') .implies('template', 'generate-hooks') .check((argv) -> + 'use strict' if argv.reporters == true showReporters() process.exit EXIT_SUCCESS @@ -80,6 +82,7 @@ configuration.options.mocha = mochaOptions abao = new Abao configuration abao.run (error, nfailures) -> + 'use strict' if error process.exitCode = EXIT_FAILURE if error.message diff --git a/lib/generate-hooks.coffee b/lib/generate-hooks.coffee index f1c4835..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' diff --git a/lib/hooks.coffee b/lib/hooks.coffee index 555ab16..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,12 +84,15 @@ 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 diff --git a/lib/test-runner.coffee b/lib/test-runner.coffee index 34e0fb3..30b3530 100644 --- a/lib/test-runner.coffee +++ b/lib/test-runner.coffee @@ -13,6 +13,7 @@ generateHooks = require './generate-hooks' class TestRunner constructor: (options, ramlFile) -> + 'use strict' @server = options.server delete options.server @mocha = new Mocha options.mocha @@ -21,6 +22,7 @@ class TestRunner @ramlFile = ramlFile addTestToMocha: (test, hooks) => + 'use strict' mocha = @mocha options = @options @@ -63,6 +65,7 @@ class TestRunner , {test} run: (tests, hooks, done) -> + 'use strict' server = @server options = @options addTestToMocha = @addTestToMocha diff --git a/lib/test.coffee b/lib/test.coffee index 67ec72f..1dc65f3 100644 --- a/lib/test.coffee +++ b/lib/test.coffee @@ -14,11 +14,13 @@ assert = chai.assert String::contains = (it) -> + 'use strict' @indexOf(it) != -1 class TestFactory constructor: (schemaLocation) -> + 'use strict' if schemaLocation files = glob.sync schemaLocation @@ -30,12 +32,14 @@ class TestFactory 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 @@ -58,6 +62,7 @@ class Test done() url: () -> + 'use strict' path = @request.server + @request.path for key, value of @request.params @@ -65,6 +70,7 @@ class Test return path run: (callback) -> + 'use strict' assertResponse = @assertResponse contentTest = @contentTest @@ -87,6 +93,7 @@ class Test ], callback assertResponse: (error, response, body) => + 'use strict' assert.isNull error assert.isNotNull response, 'Response' diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index 8368912..6ab7348 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -53,6 +53,7 @@ debugExecCommand = false execCommand = (cmd, callback) -> + 'use strict' stderr = '' stdout = '' report = '' @@ -80,6 +81,7 @@ execCommand = (cmd, callback) -> describe 'Command line interface', () -> + 'use strict' describe 'when run without any arguments', (done) -> diff --git a/test/unit/abao-test.coffee b/test/unit/abao-test.coffee index 0954f0e..c8a3124 100644 --- a/test/unit/abao-test.coffee +++ b/test/unit/abao-test.coffee @@ -25,6 +25,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 942957a..ef32ab1 100644 --- a/test/unit/add-hooks-test.coffee +++ b/test/unit/add-hooks-test.coffee @@ -16,6 +16,7 @@ addHooks = proxyquire '../../lib/add-hooks', { } describe 'addHooks(hooks, pattern)', () -> + 'use strict' transactions = {} diff --git a/test/unit/add-tests-test.coffee b/test/unit/add-tests-test.coffee index 169aa9f..a4e848a 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', () -> diff --git a/test/unit/hooks-test.coffee b/test/unit/hooks-test.coffee index 9854aad..3e395bb 100644 --- a/test/unit/hooks-test.coffee +++ b/test/unit/hooks-test.coffee @@ -9,6 +9,7 @@ hooks = require '../../lib/hooks' ABAO_IO_SERVER = 'http://abao.io' describe 'Hooks', () -> + 'use strict' describe 'when adding before hook', () -> diff --git a/test/unit/test-runner-test.coffee b/test/unit/test-runner-test.coffee index fc60cb4..3a1fcbd 100644 --- a/test/unit/test-runner-test.coffee +++ b/test/unit/test-runner-test.coffee @@ -24,6 +24,7 @@ should = chai.should() chai.use(sinonChai) describe 'Test Runner', () -> + 'use strict' runner = undefined diff --git a/test/unit/test-test.coffee b/test/unit/test-test.coffee index a0ab922..54b4443 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', () -> From 43a2f3ac0de4c1cdfa34e07c4fb5702a45a7915a Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Sun, 25 Mar 2018 05:36:19 -0500 Subject: [PATCH 19/64] test(cli-test.coffee): Enhance "--header" testing Broke test into two, testing for acceptability based on header value. The latter now triggers HTTP 406 failure. Additional minor description changes elsewhere. --- test/e2e/cli-test.coffee | 83 +++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index 6ab7348..0904b19 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -34,8 +34,6 @@ stdout = '' report = '' exitStatus = null -receivedRequest = {} - # # To dump individual raw test results: # @@ -209,7 +207,7 @@ describe 'Command line interface', () -> describe 'when invoked with "--generate-hooks" option', () -> - describe 'by itself', () -> + describe 'by itself (use package-provided template)', () -> runGenHooksTestAsync = (done) -> ramlFile = "#{RAML_DIR}/single-get.raml" @@ -415,7 +413,7 @@ describe 'Command line interface', () -> before (done) -> runRamlIncludesTestAsync done - it 'should print count of tests run', () -> + it 'should print count of passing tests run', () -> expect(stdout).to.have.string('1 passing') it 'should exit normally', () -> @@ -457,20 +455,42 @@ describe 'Command line interface', () -> describe 'when invoked with "--header" option', () -> receivedRequest = {} + producedMediaType = 'application/vnd.api+json' + reqMediaType = undefined runHeaderTestAsync = (done) -> - extraHeader = 'Accept:application/json' + extraHeader = "Accept:#{reqMediaType}" ramlFile = "#{RAML_DIR}/single-get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --header #{extraHeader}" app = express() - app.get '/machines', (req, res) -> + app.use (req, res, next) -> receivedRequest = req + next() + + app.use (req, res, next) -> + err = null + produces = ["#{producedMediaType}"] + if !req.accepts produces + err = new Error('Not Acceptable') + err.status = 406 + next(err) + + app.get '/machines', (req, res) -> machine = type: 'bulldozer' name: 'willy' - res.status(200).json([machine]) + res.setHeader 'Content-Type', "#{producedMediaType}" + res.status(200).send([machine]) + + app.use (err, req, res, next) -> + res.status(err.status || 500) + .json({ + message: err.message, + stack: err.stack + }) + return server = app.listen PORT, () -> execCommand cmd, () -> @@ -478,17 +498,41 @@ describe 'Command line interface', () -> server.on 'close', done - before (done) -> - runHeaderTestAsync done + context 'with "accept"-able request', () -> - it 'should have an additional header in the request', () -> - expect(receivedRequest.headers.accept).to.equal('application/json') + before (done) -> + reqMediaType = "#{producedMediaType}" + runHeaderTestAsync done - it 'should print count of tests run', () -> - expect(stdout).to.have.string('1 passing') + it 'should have the additional header in the request', () -> + expect(receivedRequest.headers.accept).to.equal("#{reqMediaType}") - it 'should exit normally', () -> - expect(exitStatus).to.equal(0) + 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 'with un-"accept"-able request', () -> + + before (done) -> + reqMediaType = 'application/json' + runHeaderTestAsync 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', () -> @@ -502,8 +546,11 @@ describe 'Command line interface', () -> app = express() - app.get '/machines', (req, res) -> + app.use (req, res, next) -> receivedRequest = req + next() + + app.get '/machines', (req, res) -> machine = type: 'bulldozer' name: 'willy' @@ -655,7 +702,7 @@ describe 'Command line interface', () -> expect(exitStatus).to.equal(0) - describe 'when expecting error', () -> + describe 'when expecting validation to fail', () -> runSchemaFailTestAsync = (done) -> pattern = "#{SCHEMA_DIR}/*.json" @@ -666,7 +713,7 @@ describe 'Command line interface', () -> app.get '/machines', (req, res) -> machine = - typO: 'bulldozer' # 'type' != 'typ0' + typO: 'bulldozer' # 'type' != 'typO' name: 'willy' res.status(200).json([machine]) From 8684264ad3483bbdaf586a6c391b95db23658f39 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Sun, 25 Mar 2018 06:46:42 -0500 Subject: [PATCH 20/64] refactor(server.coffee): Update server stub Added 'use strict' to eliminate warnings. Added JSON error reporting. Modified port handling and reporting. --- test/stub/server.coffee | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/test/stub/server.coffee b/test/stub/server.coffee index 9770482..24b6b51 100644 --- a/test/stub/server.coffee +++ b/test/stub/server.coffee @@ -1,18 +1,31 @@ -express = require 'express' +###* +# @file Server stub +### +require 'coffee-script/register' -PORT = '3333' +express = require 'express' app = express() +app.set 'port', process.env.PORT || 3333 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 From 72e3f348af174d0dedb5a76de7f828ae11a65a6c Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Sun, 25 Mar 2018 06:51:07 -0500 Subject: [PATCH 21/64] test(test/fixtures/test_hooks.coffee): Eliminate lint warning Added 'use strict' to hookfile function. --- test/fixtures/test_hooks.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/fixtures/test_hooks.coffee b/test/fixtures/test_hooks.coffee index 40f3177..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) -> + 'use strict' console.error 'after-hook-GET-machines' done() + From 8b68b328f0b7039fbcbc82a775caf617d36d84f6 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Sun, 25 Mar 2018 07:44:13 -0500 Subject: [PATCH 22/64] test(test/unit/hooks-test.coffee): Eliminate lint warnings Replaced various empty function calls with named `noop()` function. --- test/unit/hooks-test.coffee | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/test/unit/hooks-test.coffee b/test/unit/hooks-test.coffee index 3e395bb..f23de6f 100644 --- a/test/unit/hooks-test.coffee +++ b/test/unit/hooks-test.coffee @@ -11,11 +11,13 @@ 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 = {} @@ -26,8 +28,8 @@ describe 'Hooks', () -> describe 'when adding after hook', () -> before () -> - hooks.after 'afterHook', () -> - '' + hooks.after 'afterHook', noop + after () -> hooks.afterHooks = {} @@ -75,7 +77,7 @@ 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) -> @@ -120,7 +122,7 @@ 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) -> @@ -131,14 +133,14 @@ describe 'Hooks', () -> 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}, () -> @@ -352,8 +354,8 @@ describe 'Hooks', () -> 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 () -> @@ -361,9 +363,9 @@ describe 'Hooks', () -> 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}" From 12d8354ad7b33de890256e223c5b3eadc872fcdb Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 26 Mar 2018 08:46:06 -0500 Subject: [PATCH 23/64] test(test/e2e/cli-test.coffee): Reparent existing "--header" test Added Accept-specific context and migrated existing tests there. --- test/e2e/cli-test.coffee | 115 ++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index 0904b19..58c1772 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -457,82 +457,85 @@ describe 'Command line interface', () -> receivedRequest = {} producedMediaType = 'application/vnd.api+json' reqMediaType = undefined + extraHeader = undefined - runHeaderTestAsync = (done) -> - extraHeader = "Accept:#{reqMediaType}" - ramlFile = "#{RAML_DIR}/single-get.raml" - cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --header #{extraHeader}" + describe 'with "Accept" header', () -> - app = express() + runAcceptHeaderTestAsync = (done) -> + extraHeader = "Accept:#{reqMediaType}" + ramlFile = "#{RAML_DIR}/single-get.raml" + cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --header #{extraHeader}" - app.use (req, res, next) -> - receivedRequest = req - next() + app = express() - app.use (req, res, next) -> - err = null - produces = ["#{producedMediaType}"] - if !req.accepts produces - err = new Error('Not Acceptable') - err.status = 406 - next(err) + app.use (req, res, next) -> + receivedRequest = req + next() - app.get '/machines', (req, res) -> - machine = - type: 'bulldozer' - name: 'willy' - res.setHeader 'Content-Type', "#{producedMediaType}" - res.status(200).send([machine]) + app.use (req, res, next) -> + err = null + produces = ["#{producedMediaType}"] + if !req.accepts produces + err = new Error('Not Acceptable') + err.status = 406 + next(err) - app.use (err, req, res, next) -> - res.status(err.status || 500) - .json({ - message: err.message, - stack: err.stack - }) - return + app.get '/machines', (req, res) -> + machine = + type: 'bulldozer' + name: 'willy' + res.setHeader 'Content-Type', "#{producedMediaType}" + res.status(200).send([machine]) - server = app.listen PORT, () -> - execCommand cmd, () -> - server.close() + app.use (err, req, res, next) -> + res.status(err.status || 500) + .json({ + message: err.message, + stack: err.stack + }) + return - server.on 'close', done + server = app.listen PORT, () -> + execCommand cmd, () -> + server.close() - context 'with "accept"-able request', () -> + server.on 'close', done - before (done) -> - reqMediaType = "#{producedMediaType}" - runHeaderTestAsync done + context 'when expecting success', () -> - it 'should have the additional header in the request', () -> - expect(receivedRequest.headers.accept).to.equal("#{reqMediaType}") + before (done) -> + reqMediaType = "#{producedMediaType}" + runAcceptHeaderTestAsync done - it 'should print count of passing tests run', () -> - expect(stdout).to.have.string('1 passing') + it 'should have the additional header in the request', () -> + expect(receivedRequest.headers.accept).to.equal("#{reqMediaType}") - it 'should exit normally', () -> - expect(exitStatus).to.equal(0) + 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 'with un-"accept"-able request', () -> - before (done) -> - reqMediaType = 'application/json' - runHeaderTestAsync done + context 'when expecting failure', () -> - it 'should have the additional header in the request', () -> - expect(receivedRequest.headers.accept).to.equal("#{reqMediaType}") + before (done) -> + reqMediaType = 'application/json' + runAcceptHeaderTestAsync done - # 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 have the additional header in the request', () -> + expect(receivedRequest.headers.accept).to.equal("#{reqMediaType}") - it 'should run test but not complete', () -> - expect(stdout).to.have.string('1 failing') + # 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 exit due to error', () -> - expect(exitStatus).to.equal(1) + 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', () -> From 2426d9a69f1e862dc437b4c42c9b9507904acbc1 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 26 Mar 2018 12:41:10 -0500 Subject: [PATCH 24/64] test(test/fixtures/*.raml,test/e2e/cli-test.coffee,test/unit/add-tests-test.coffee,README.md): Renam Renamed RAML files as appropriate. Updated affected tests and README. --- README.md | 8 ++--- test/e2e/cli-test.coffee | 32 +++++++++---------- test/fixtures/contacts.raml | 8 +++++ ...1-post.raml => machines-1_get_1_post.raml} | 6 ++++ ....raml => machines-include_other_raml.raml} | 0 ...machines-inline_and_included_schemas.raml} | 0 ...no-method.raml => machines-no_method.raml} | 0 ...achines-non_required_query_parameter.raml} | 0 ...s.raml => machines-ref_other_schemas.raml} | 0 ...=> machines-required_query_parameter.raml} | 0 ...ngle-get.raml => machines-single_get.raml} | 0 ...levels.raml => machines-three_levels.raml} | 0 ...refs.raml => machines-with_json_refs.raml} | 0 ...o-base-uri.raml => music-no_base_uri.raml} | 1 + .../{simple.raml => music-simple.raml} | 1 + ...pe.raml => music-vendor_content_type.raml} | 0 test/unit/add-tests-test.coffee | 29 +++++++---------- 17 files changed, 48 insertions(+), 37 deletions(-) rename test/fixtures/{1-get-1-post.raml => machines-1_get_1_post.raml} (71%) rename test/fixtures/{include_other_raml.raml => machines-include_other_raml.raml} (100%) rename test/fixtures/{inline_and_included_schemas.raml => machines-inline_and_included_schemas.raml} (100%) rename test/fixtures/{no-method.raml => machines-no_method.raml} (100%) rename test/fixtures/{non_required_query_parameter.raml => machines-non_required_query_parameter.raml} (100%) rename test/fixtures/{ref_other_schemas.raml => machines-ref_other_schemas.raml} (100%) rename test/fixtures/{required_query_parameter.raml => machines-required_query_parameter.raml} (100%) rename test/fixtures/{single-get.raml => machines-single_get.raml} (100%) rename test/fixtures/{three-levels.raml => machines-three_levels.raml} (100%) rename test/fixtures/{with-json-refs.raml => machines-with_json_refs.raml} (100%) rename test/fixtures/{no-base-uri.raml => music-no_base_uri.raml} (95%) rename test/fixtures/{simple.raml => music-simple.raml} (95%) rename test/fixtures/{vendor-content-type.raml => music-vendor_content_type.raml} (100%) diff --git a/README.md b/README.md index 2d2110f..fa719a8 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index 58c1772..20cbdc6 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -105,7 +105,7 @@ describe 'Command line interface', () -> describe 'when run with multiple positional arguments', (done) -> runTooManyArgTestAsync = (done) -> - ramlFile = "#{RAML_DIR}/single-get.raml" + ramlFile = "#{RAML_DIR}/machines-single_get.raml" cmd = "#{ABAO_BIN} #{ramlFile} #{ramlFile}" execCommand cmd, done @@ -187,7 +187,7 @@ describe 'Command line interface', () -> describe 'when invoked with "--names" option', () -> runNamesTestAsync = (done) -> - ramlFile = "#{RAML_DIR}/single-get.raml" + ramlFile = "#{RAML_DIR}/machines-single_get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --names" execCommand cmd, done @@ -210,7 +210,7 @@ describe 'Command line interface', () -> describe 'by itself (use package-provided template)', () -> runGenHooksTestAsync = (done) -> - ramlFile = "#{RAML_DIR}/single-get.raml" + ramlFile = "#{RAML_DIR}/machines-single_get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --generate-hooks" execCommand cmd, done @@ -232,7 +232,7 @@ describe 'Command line interface', () -> 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 @@ -254,7 +254,7 @@ describe 'Command line interface', () -> 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 @@ -297,7 +297,7 @@ describe 'Command line interface', () -> describe 'when RAML file does not specify "baseUri"', () -> runUnspecifiedServerTestAsync = (done) -> - ramlFile = "#{RAML_DIR}/no-base-uri.raml" + ramlFile = "#{RAML_DIR}/music-no_base_uri.raml" cmd = "#{ABAO_BIN} #{ramlFile} --reporter json" execCommand cmd, done @@ -317,7 +317,7 @@ describe 'Command line interface', () -> resTestTitle = 'GET /machines -> 200 Validate response code and body' runBaseUriServerTestAsync = (done) -> - ramlFile = "#{RAML_DIR}/single-get.raml" + ramlFile = "#{RAML_DIR}/machines-single_get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --reporter json" app = express() @@ -356,7 +356,7 @@ describe 'Command line interface', () -> resTestTitle = 'GET /machines -> 200 Validate response code and body' runNormalTestAsync = (done) -> - ramlFile = "#{RAML_DIR}/single-get.raml" + ramlFile = "#{RAML_DIR}/machines-single_get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --reporter json" app = express() @@ -393,7 +393,7 @@ describe 'Command line interface', () -> describe 'when executing the command and RAML includes other RAML files', () -> runRamlIncludesTestAsync = (done) -> - ramlFile = "#{RAML_DIR}/include_other_raml.raml" + ramlFile = "#{RAML_DIR}/machines-include_other_raml.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER}" app = express() @@ -425,7 +425,7 @@ describe 'Command line interface', () -> describe 'when invoked with "--reporter" option', () -> runReporterTestAsync = (done) -> - ramlFile = "#{RAML_DIR}/single-get.raml" + ramlFile = "#{RAML_DIR}/machines-single_get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --reporter spec" app = express() @@ -463,7 +463,7 @@ describe 'Command line interface', () -> runAcceptHeaderTestAsync = (done) -> extraHeader = "Accept:#{reqMediaType}" - ramlFile = "#{RAML_DIR}/single-get.raml" + ramlFile = "#{RAML_DIR}/machines-single_get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --header #{extraHeader}" app = express() @@ -544,7 +544,7 @@ describe 'Command line interface', () -> runHookfilesTestAsync = (done) -> pattern = "#{HOOK_DIR}/*_hooks.*" - ramlFile = "#{RAML_DIR}/single-get.raml" + ramlFile = "#{RAML_DIR}/machines-single_get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --hookfiles=#{pattern}" app = express() @@ -583,7 +583,7 @@ describe 'Command line interface', () -> describe 'when invoked with "--hooks-only" option', () -> runHooksOnlyTestAsync = (done) -> - ramlFile = "#{RAML_DIR}/single-get.raml" + ramlFile = "#{RAML_DIR}/machines-single_get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --hooks-only" app = express() @@ -617,7 +617,7 @@ describe 'Command line interface', () -> finished = undefined runTimeoutTestAsync = (done) -> - ramlFile = "#{RAML_DIR}/single-get.raml" + ramlFile = "#{RAML_DIR}/machines-single_get.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --timeout #{timeout}" beginTime = undefined @@ -681,7 +681,7 @@ describe 'Command line interface', () -> runSchemaTestAsync = (done) -> pattern = "#{SCHEMA_DIR}/*.json" - ramlFile = "#{RAML_DIR}/with-json-refs.raml" + ramlFile = "#{RAML_DIR}/machines-with_json_refs.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --schemas=#{pattern}" app = express() @@ -709,7 +709,7 @@ describe 'Command line interface', () -> runSchemaFailTestAsync = (done) -> pattern = "#{SCHEMA_DIR}/*.json" - ramlFile = "#{RAML_DIR}/with-json-refs.raml" + ramlFile = "#{RAML_DIR}/machines-with_json_refs.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --schemas=#{pattern}" app = express() diff --git a/test/fixtures/contacts.raml b/test/fixtures/contacts.raml index 9231afa..c40d4d2 100644 --- a/test/fixtures/contacts.raml +++ b/test/fixtures/contacts.raml @@ -15,6 +15,11 @@ version: v1 { "type": "Kulu", "name": "Mike" } responses: 201: + description: "Returns a newly created contact, with server-controlled fields like 'id' populated" + headers: + location: + description: URI of the newly created contact + example: {baseUri}/contacts/{id} body: application/json: schema: | @@ -26,6 +31,7 @@ version: v1 delete: responses: 204: + description: "Deletes an existing contact" put: body: application/json: @@ -36,6 +42,7 @@ version: v1 { "type": "Kulu", "name": "Mike" } responses: 201: + description: "Replaces body of an existing contact" body: application/json: schema: | @@ -46,6 +53,7 @@ version: v1 get: responses: 200: + description: "Returns an existing contact" body: application/json: schema: | diff --git a/test/fixtures/1-get-1-post.raml b/test/fixtures/machines-1_get_1_post.raml similarity index 71% rename from test/fixtures/1-get-1-post.raml rename to test/fixtures/machines-1_get_1_post.raml index b656a52..ee9da23 100644 --- a/test/fixtures/1-get-1-post.raml +++ b/test/fixtures/machines-1_get_1_post.raml @@ -8,6 +8,7 @@ version: v1 get: responses: 200: + description: "Returns an existing machine" body: application/json: schema: | @@ -27,6 +28,11 @@ version: v1 { "type": "Kulu", "name": "Mike" } responses: 201: + description: "Returns a newly created machine, with server-controlled fields like 'id' populated" + headers: + location: + description: URI of the newly created machine + example: {baseUri}/machines/{id} body: application/json: schema: | diff --git a/test/fixtures/include_other_raml.raml b/test/fixtures/machines-include_other_raml.raml similarity index 100% rename from test/fixtures/include_other_raml.raml rename to test/fixtures/machines-include_other_raml.raml diff --git a/test/fixtures/inline_and_included_schemas.raml b/test/fixtures/machines-inline_and_included_schemas.raml similarity index 100% rename from test/fixtures/inline_and_included_schemas.raml rename to test/fixtures/machines-inline_and_included_schemas.raml diff --git a/test/fixtures/no-method.raml b/test/fixtures/machines-no_method.raml similarity index 100% rename from test/fixtures/no-method.raml rename to test/fixtures/machines-no_method.raml diff --git a/test/fixtures/non_required_query_parameter.raml b/test/fixtures/machines-non_required_query_parameter.raml similarity index 100% rename from test/fixtures/non_required_query_parameter.raml rename to test/fixtures/machines-non_required_query_parameter.raml diff --git a/test/fixtures/ref_other_schemas.raml b/test/fixtures/machines-ref_other_schemas.raml similarity index 100% rename from test/fixtures/ref_other_schemas.raml rename to test/fixtures/machines-ref_other_schemas.raml diff --git a/test/fixtures/required_query_parameter.raml b/test/fixtures/machines-required_query_parameter.raml similarity index 100% rename from test/fixtures/required_query_parameter.raml rename to test/fixtures/machines-required_query_parameter.raml diff --git a/test/fixtures/single-get.raml b/test/fixtures/machines-single_get.raml similarity index 100% rename from test/fixtures/single-get.raml rename to test/fixtures/machines-single_get.raml diff --git a/test/fixtures/three-levels.raml b/test/fixtures/machines-three_levels.raml similarity index 100% rename from test/fixtures/three-levels.raml rename to test/fixtures/machines-three_levels.raml 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 diff --git a/test/fixtures/no-base-uri.raml b/test/fixtures/music-no_base_uri.raml similarity index 95% rename from test/fixtures/no-base-uri.raml rename to test/fixtures/music-no_base_uri.raml index 32aa268..f661eb8 100644 --- a/test/fixtures/no-base-uri.raml +++ b/test/fixtures/music-no_base_uri.raml @@ -19,6 +19,7 @@ traits: get: responses: 200: + description: "Returns an existing song" body: application/json: schema: | diff --git a/test/fixtures/simple.raml b/test/fixtures/music-simple.raml similarity index 95% rename from test/fixtures/simple.raml rename to test/fixtures/music-simple.raml index 4086a7e..ccc7417 100644 --- a/test/fixtures/simple.raml +++ b/test/fixtures/music-simple.raml @@ -20,6 +20,7 @@ traits: get: responses: 200: + description: "Returns an existing song" body: application/json: schema: | diff --git a/test/fixtures/vendor-content-type.raml b/test/fixtures/music-vendor_content_type.raml similarity index 100% rename from test/fixtures/vendor-content-type.raml rename to test/fixtures/music-vendor_content_type.raml diff --git a/test/unit/add-tests-test.coffee b/test/unit/add-tests-test.coffee index a4e848a..398d7ba 100644 --- a/test/unit/add-tests-test.coffee +++ b/test/unit/add-tests-test.coffee @@ -28,7 +28,7 @@ describe '#addTests', () -> callback = '' before (done) -> - ramlFile = "#{RAML_DIR}/single-get.raml" + ramlFile = "#{RAML_DIR}/machines-single_get.raml" ramlParser.loadFile(ramlFile) .then (raml) -> callback = sinon.stub() @@ -77,8 +77,7 @@ describe '#addTests', () -> callback = '' 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() @@ -131,8 +130,7 @@ describe '#addTests', () -> callback = '' 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() @@ -185,8 +183,7 @@ describe '#addTests', () -> callback = '' 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() @@ -230,8 +227,7 @@ describe '#addTests', () -> callback = '' 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() @@ -275,8 +271,7 @@ describe '#addTests', () -> callback = '' before (done) -> - - ramlFile = "#{RAML_DIR}/three-levels.raml" + ramlFile = "#{RAML_DIR}/machines-three_levels.raml" ramlParser.loadFile(ramlFile) .then (raml) -> callback = sinon.stub() @@ -316,8 +311,7 @@ describe '#addTests', () -> callback = '' before (done) -> - - ramlFile = "#{RAML_DIR}/no-method.raml" + ramlFile = "#{RAML_DIR}/machines-no_method.raml" ramlParser.loadFile(ramlFile) .then (raml) -> callback = sinon.stub() @@ -390,7 +384,7 @@ describe '#addTests', () -> callback = '' 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() @@ -436,8 +430,8 @@ describe '#addTests', () -> callback = '' before (done) -> - - ramlParser.loadFile("#{RAML_DIR}/required_query_parameter.raml") + ramlFile ="#{RAML_DIR}/machines-required_query_parameter.raml" + ramlParser.loadFile(ramlFile) .then (raml) -> callback = sinon.stub() callback.returns(done()) @@ -457,7 +451,8 @@ describe '#addTests', () -> callback = '' before (done) -> - ramlParser.loadFile("#{RAML_DIR}/non_required_query_parameter.raml") + ramlFile = "#{RAML_DIR}/machines-non_required_query_parameter.raml" + ramlParser.loadFile(ramlFile) .then (raml) -> callback = sinon.stub() callback.returns(done()) From cf155cf5394ab06bb55d0b7d33dac3c9036c222d Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 26 Mar 2018 12:55:52 -0500 Subject: [PATCH 25/64] style(tests/unit/add-tests-test.coffee): Improve test readability Added newlines where needed to better separate where tests begin/end. [ci skip] --- test/unit/add-tests-test.coffee | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/test/unit/add-tests-test.coffee b/test/unit/add-tests-test.coffee index 398d7ba..da66b7c 100644 --- a/test/unit/add-tests-test.coffee +++ b/test/unit/add-tests-test.coffee @@ -36,6 +36,7 @@ describe '#addTests', () -> addTests raml, tests, hooks, callback, testFactory, false return + after () -> tests = [] @@ -69,7 +70,9 @@ 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 = [] @@ -85,6 +88,7 @@ describe '#addTests', () -> addTests raml, tests, hooks, callback, testFactory, false return + after () -> tests = [] @@ -123,6 +127,7 @@ describe '#addTests', () -> assert.isNull res.headers assert.isNull res.body + describe 'when processed in order specified by "--sorted" option', () -> tests = [] @@ -138,6 +143,7 @@ describe '#addTests', () -> addTests raml, tests, hooks, null, callback, testFactory, true return + after () -> tests = [] @@ -176,6 +182,7 @@ describe '#addTests', () -> assert.isNull res.headers assert.isNull res.body + describe 'when RAML includes multiple referencing schemas', () -> tests = [] @@ -191,6 +198,7 @@ describe '#addTests', () -> addTests raml, tests, hooks, callback, testFactory, false return + after () -> tests = [] @@ -220,6 +228,7 @@ describe '#addTests', () -> assert.isNull res.headers assert.isNull res.body + describe 'when RAML has inline and included schemas', () -> tests = [] @@ -235,6 +244,7 @@ describe '#addTests', () -> addTests raml, tests, hooks, callback, testFactory, false return + after () -> tests = [] @@ -264,6 +274,7 @@ describe '#addTests', () -> assert.isNull res.headers assert.isNull res.body + describe 'when RAML contains three-levels endpoints', () -> tests = [] @@ -304,6 +315,7 @@ describe '#addTests', () -> assert.deepEqual test.request.params, machine_id: '1' + describe 'when RAML has resource not defined method', () -> tests = [] @@ -332,6 +344,7 @@ 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 = [] @@ -339,7 +352,6 @@ describe '#addTests', () -> callback = '' before (done) -> - raml = """ #%RAML 0.8 @@ -378,7 +390,9 @@ 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 = '' @@ -392,6 +406,7 @@ describe '#addTests', () -> addTests raml, tests, hooks, callback, testFactory, false return + after () -> tests = [] @@ -425,6 +440,7 @@ describe '#addTests', () -> describe 'when there is required query parameter with example value', () -> + tests = [] testFactory = new TestFactory() callback = '' @@ -445,7 +461,9 @@ describe '#addTests', () -> 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 = '' @@ -459,8 +477,10 @@ describe '#addTests', () -> addTests raml, tests, hooks, callback, testFactory, false return + after () -> tests = [] it 'should not append query parameters', () -> assert.deepEqual tests[0].request.query, {} + From d12eea421889df8ffd07f24236de827fcc11827c Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 26 Mar 2018 18:10:27 -0500 Subject: [PATCH 26/64] test(test/fixtures/*.raml): Make necessary corrections to RAML Previous commit for renaming RAML files accidentally included untested modifications. Broken parts have been corrected or removed. --- test/fixtures/contacts.raml | 12 ++++++------ test/fixtures/machines-1_get_1_post.raml | 6 +++--- test/fixtures/machines-include_other_raml.raml | 1 + .../machines-inline_and_included_schemas.raml | 1 + test/fixtures/machines-no_method.raml | 1 + .../machines-non_required_query_parameter.raml | 1 + test/fixtures/machines-ref_other_schemas.raml | 1 + test/fixtures/machines-required_query_parameter.raml | 1 + test/fixtures/machines-single_get.raml | 1 + test/fixtures/machines-three_levels.raml | 3 +++ test/fixtures/machines-with_json_refs.raml | 2 +- test/fixtures/music-no_base_uri.raml | 7 ++++--- test/fixtures/music-simple.raml | 7 ++++--- test/fixtures/music-vendor_content_type.raml | 1 + 14 files changed, 29 insertions(+), 16 deletions(-) diff --git a/test/fixtures/contacts.raml b/test/fixtures/contacts.raml index c40d4d2..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,11 +16,10 @@ version: v1 { "type": "Kulu", "name": "Mike" } responses: 201: - description: "Returns a newly created contact, with server-controlled fields like 'id' populated" headers: location: description: URI of the newly created contact - example: {baseUri}/contacts/{id} + example: /contacts/{contact_id} body: application/json: schema: | @@ -27,12 +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: - description: "Deletes an existing contact" put: + description: Replaces an existing contact by `contact_id` body: application/json: schema: | @@ -42,7 +43,6 @@ version: v1 { "type": "Kulu", "name": "Mike" } responses: 201: - description: "Replaces body of an existing contact" body: application/json: schema: | @@ -51,9 +51,9 @@ version: v1 example: | { "type": "Kulu", "name": "Mike" } get: + description: Gets an existing contact by `contact_id` responses: 200: - description: "Returns an existing contact" body: application/json: schema: | diff --git a/test/fixtures/machines-1_get_1_post.raml b/test/fixtures/machines-1_get_1_post.raml index ee9da23..d2d2e2b 100644 --- a/test/fixtures/machines-1_get_1_post.raml +++ b/test/fixtures/machines-1_get_1_post.raml @@ -6,9 +6,9 @@ version: v1 /machines: get: + description: Get a list of existing machines responses: 200: - description: "Returns an existing machine" body: application/json: schema: | @@ -19,6 +19,7 @@ version: v1 example: | { "type": "Kulu", "name": "Mike" } post: + description: Creates a new machine body: application/json: schema: | @@ -28,11 +29,10 @@ version: v1 { "type": "Kulu", "name": "Mike" } responses: 201: - description: "Returns a newly created machine, with server-controlled fields like 'id' populated" headers: location: description: URI of the newly created machine - example: {baseUri}/machines/{id} + example: /machines/{id} body: application/json: schema: | diff --git a/test/fixtures/machines-include_other_raml.raml b/test/fixtures/machines-include_other_raml.raml index 895add6..1141953 100644 --- a/test/fixtures/machines-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/machines-inline_and_included_schemas.raml b/test/fixtures/machines-inline_and_included_schemas.raml index 0357800..e3ab190 100644 --- a/test/fixtures/machines-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/machines-no_method.raml b/test/fixtures/machines-no_method.raml index b9ae3a2..e145269 100644 --- a/test/fixtures/machines-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/machines-non_required_query_parameter.raml b/test/fixtures/machines-non_required_query_parameter.raml index 56264cf..5466f0b 100644 --- a/test/fixtures/machines-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/machines-ref_other_schemas.raml b/test/fixtures/machines-ref_other_schemas.raml index 211e7df..728867c 100644 --- a/test/fixtures/machines-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/machines-required_query_parameter.raml b/test/fixtures/machines-required_query_parameter.raml index 0fb5a23..4e84652 100644 --- a/test/fixtures/machines-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/machines-single_get.raml b/test/fixtures/machines-single_get.raml index f0e7316..6af46da 100644 --- a/test/fixtures/machines-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/machines-three_levels.raml b/test/fixtures/machines-three_levels.raml index 9b03f99..30ec089 100644 --- a/test/fixtures/machines-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/machines-with_json_refs.raml b/test/fixtures/machines-with_json_refs.raml index 640369a..cb1bbbb 100644 --- a/test/fixtures/machines-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/music-no_base_uri.raml b/test/fixtures/music-no_base_uri.raml index f661eb8..cf7c133 100644 --- a/test/fixtures/music-no_base_uri.raml +++ b/test/fixtures/music-no_base_uri.raml @@ -11,15 +11,17 @@ 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: - description: "Returns an existing song" body: application/json: schema: | @@ -36,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/music-simple.raml b/test/fixtures/music-simple.raml index ccc7417..d134fcc 100644 --- a/test/fixtures/music-simple.raml +++ b/test/fixtures/music-simple.raml @@ -12,15 +12,17 @@ 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: - description: "Returns an existing song" body: application/json: schema: | @@ -37,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/music-vendor_content_type.raml b/test/fixtures/music-vendor_content_type.raml index 199c17f..ce76a2e 100644 --- a/test/fixtures/music-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: | From 1befcc4351782c589a4ee8673028defa8ac4c5b0 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 26 Mar 2018 18:14:33 -0500 Subject: [PATCH 27/64] test(tests/unit/add-tests-test.coffee): Add promise error handling to tests `.catch` blocks were added to all tests to ensure Mocha can detect test completion. --- test/unit/add-tests-test.coffee | 55 ++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/test/unit/add-tests-test.coffee b/test/unit/add-tests-test.coffee index da66b7c..6a41c50 100644 --- a/test/unit/add-tests-test.coffee +++ b/test/unit/add-tests-test.coffee @@ -25,7 +25,7 @@ describe '#addTests', () -> tests = [] testFactory = new TestFactory() - callback = '' + callback = undefined before (done) -> ramlFile = "#{RAML_DIR}/machines-single_get.raml" @@ -35,6 +35,9 @@ describe '#addTests', () -> callback.returns(done()) addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -77,7 +80,7 @@ describe '#addTests', () -> tests = [] testFactory = new TestFactory() - callback = '' + callback = undefined before (done) -> ramlFile = "#{RAML_DIR}/machines-1_get_1_post.raml" @@ -87,6 +90,9 @@ describe '#addTests', () -> callback.returns(done()) addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -132,7 +138,7 @@ describe '#addTests', () -> tests = [] testFactory = new TestFactory() - callback = '' + callback = undefined before (done) -> ramlFile = "#{RAML_DIR}/machines-1_get_1_post.raml" @@ -142,6 +148,9 @@ describe '#addTests', () -> callback.returns(done()) addTests raml, tests, hooks, null, callback, testFactory, true + .catch (err) -> + console.error err + done(err) return after () -> @@ -187,7 +196,7 @@ describe '#addTests', () -> tests = [] testFactory = new TestFactory() - callback = '' + callback = undefined before (done) -> ramlFile = "#{RAML_DIR}/machines-ref_other_schemas.raml" @@ -197,6 +206,9 @@ describe '#addTests', () -> callback.returns(done()) addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -233,7 +245,7 @@ describe '#addTests', () -> tests = [] testFactory = new TestFactory() - callback = '' + callback = undefined before (done) -> ramlFile = "#{RAML_DIR}/machines-inline_and_included_schemas.raml" @@ -243,6 +255,9 @@ describe '#addTests', () -> callback.returns(done()) addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -279,7 +294,7 @@ describe '#addTests', () -> tests = [] testFactory = new TestFactory() - callback = '' + callback = undefined before (done) -> ramlFile = "#{RAML_DIR}/machines-three_levels.raml" @@ -289,6 +304,9 @@ describe '#addTests', () -> callback.returns(done()) addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -320,7 +338,7 @@ describe '#addTests', () -> tests = [] testFactory = new TestFactory() - callback = '' + callback = undefined before (done) -> ramlFile = "#{RAML_DIR}/machines-no_method.raml" @@ -330,6 +348,9 @@ describe '#addTests', () -> callback.returns(done()) addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -349,7 +370,7 @@ describe '#addTests', () -> tests = [] testFactory = new TestFactory() - callback = '' + callback = undefined before (done) -> raml = """ @@ -374,6 +395,9 @@ describe '#addTests', () -> sinon.stub console, 'warn' addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -395,7 +419,7 @@ describe '#addTests', () -> tests = [] testFactory = new TestFactory() - callback = '' + callback = undefined before (done) -> ramlFile = "#{RAML_DIR}/music-vendor_content_type.raml" @@ -405,6 +429,9 @@ describe '#addTests', () -> callback.returns(done()) addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -443,7 +470,7 @@ describe '#addTests', () -> tests = [] testFactory = new TestFactory() - callback = '' + callback = undefined before (done) -> ramlFile ="#{RAML_DIR}/machines-required_query_parameter.raml" @@ -453,6 +480,9 @@ describe '#addTests', () -> callback.returns(done()) addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -466,7 +496,7 @@ describe '#addTests', () -> tests = [] testFactory = new TestFactory() - callback = '' + callback = undefined before (done) -> ramlFile = "#{RAML_DIR}/machines-non_required_query_parameter.raml" @@ -476,6 +506,9 @@ describe '#addTests', () -> callback.returns(done()) addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> From 9a57e438f103dcde867602a89dccd71702f00512 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 26 Mar 2018 19:38:06 -0500 Subject: [PATCH 28/64] style(test/unit/add-tests-test.coffee): Reformat to indent promise code blocks --- test/unit/add-tests-test.coffee | 180 ++++++++++++++++---------------- 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/test/unit/add-tests-test.coffee b/test/unit/add-tests-test.coffee index 6a41c50..b47f714 100644 --- a/test/unit/add-tests-test.coffee +++ b/test/unit/add-tests-test.coffee @@ -30,14 +30,14 @@ describe '#addTests', () -> before (done) -> ramlFile = "#{RAML_DIR}/machines-single_get.raml" ramlParser.loadFile(ramlFile) - .then (raml) -> - callback = sinon.stub() - callback.returns(done()) - - addTests raml, tests, hooks, callback, testFactory, false - .catch (err) -> - console.error err - done(err) + .then (raml) -> + callback = sinon.stub() + callback.returns(done()) + + addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -85,14 +85,14 @@ describe '#addTests', () -> before (done) -> 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 - .catch (err) -> - console.error err - done(err) + .then (raml) -> + callback = sinon.stub() + callback.returns(done()) + + addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -143,14 +143,14 @@ describe '#addTests', () -> before (done) -> 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 - .catch (err) -> - console.error err - done(err) + .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 () -> @@ -201,14 +201,14 @@ describe '#addTests', () -> before (done) -> ramlFile = "#{RAML_DIR}/machines-ref_other_schemas.raml" ramlParser.loadFile(ramlFile) - .then (raml) -> - callback = sinon.stub() - callback.returns(done()) - - addTests raml, tests, hooks, callback, testFactory, false - .catch (err) -> - console.error err - done(err) + .then (raml) -> + callback = sinon.stub() + callback.returns(done()) + + addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -250,14 +250,14 @@ describe '#addTests', () -> before (done) -> ramlFile = "#{RAML_DIR}/machines-inline_and_included_schemas.raml" ramlParser.loadFile(ramlFile) - .then (raml) -> - callback = sinon.stub() - callback.returns(done()) - - addTests raml, tests, hooks, callback, testFactory, false - .catch (err) -> - console.error err - done(err) + .then (raml) -> + callback = sinon.stub() + callback.returns(done()) + + addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -299,14 +299,14 @@ describe '#addTests', () -> before (done) -> ramlFile = "#{RAML_DIR}/machines-three_levels.raml" ramlParser.loadFile(ramlFile) - .then (raml) -> - callback = sinon.stub() - callback.returns(done()) - - addTests raml, tests, hooks, callback, testFactory, false - .catch (err) -> - console.error err - done(err) + .then (raml) -> + callback = sinon.stub() + callback.returns(done()) + + addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -343,14 +343,14 @@ describe '#addTests', () -> before (done) -> ramlFile = "#{RAML_DIR}/machines-no_method.raml" ramlParser.loadFile(ramlFile) - .then (raml) -> - callback = sinon.stub() - callback.returns(done()) - - addTests raml, tests, hooks, callback, testFactory, false - .catch (err) -> - console.error err - done(err) + .then (raml) -> + callback = sinon.stub() + callback.returns(done()) + + addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -389,15 +389,15 @@ describe '#addTests', () -> 204: """ ramlParser.load(raml) - .then (raml) -> - callback = sinon.stub() - callback.returns(done()) - - sinon.stub console, 'warn' - addTests raml, tests, hooks, callback, testFactory, false - .catch (err) -> - console.error err - done(err) + .then (raml) -> + callback = sinon.stub() + callback.returns(done()) + + sinon.stub console, 'warn' + addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -424,14 +424,14 @@ describe '#addTests', () -> before (done) -> ramlFile = "#{RAML_DIR}/music-vendor_content_type.raml" ramlParser.loadFile(ramlFile) - .then (raml) -> - callback = sinon.stub() - callback.returns(done()) - - addTests raml, tests, hooks, callback, testFactory, false - .catch (err) -> - console.error err - done(err) + .then (raml) -> + callback = sinon.stub() + callback.returns(done()) + + addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -473,16 +473,16 @@ describe '#addTests', () -> callback = undefined before (done) -> - ramlFile ="#{RAML_DIR}/machines-required_query_parameter.raml" + ramlFile = "#{RAML_DIR}/machines-required_query_parameter.raml" ramlParser.loadFile(ramlFile) - .then (raml) -> - callback = sinon.stub() - callback.returns(done()) - - addTests raml, tests, hooks, callback, testFactory, false - .catch (err) -> - console.error err - done(err) + .then (raml) -> + callback = sinon.stub() + callback.returns(done()) + + addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> @@ -501,14 +501,14 @@ describe '#addTests', () -> before (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 - .catch (err) -> - console.error err - done(err) + .then (raml) -> + callback = sinon.stub() + callback.returns(done()) + + addTests raml, tests, hooks, callback, testFactory, false + .catch (err) -> + console.error err + done(err) return after () -> From c5b88724a30f0661c6454674cf62bab547dabacf Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 26 Mar 2018 19:40:47 -0500 Subject: [PATCH 29/64] test(tests/unit/add-tests-test.coffee): Add minor checks to last two tests Last two tests were not verifying callback was called and test was added. --- test/unit/add-tests-test.coffee | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/unit/add-tests-test.coffee b/test/unit/add-tests-test.coffee index b47f714..878b85a 100644 --- a/test/unit/add-tests-test.coffee +++ b/test/unit/add-tests-test.coffee @@ -488,6 +488,12 @@ describe '#addTests', () -> 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' @@ -514,6 +520,12 @@ describe '#addTests', () -> 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, {} From 8cde4ff992c189d7a11586449fa589c0acffa8a7 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 28 Mar 2018 06:13:18 -0500 Subject: [PATCH 30/64] test(test/stub/server.coffee): Add OPTIONS processing --- test/stub/server.coffee | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/stub/server.coffee b/test/stub/server.coffee index 24b6b51..5fb52e5 100644 --- a/test/stub/server.coffee +++ b/test/stub/server.coffee @@ -1,5 +1,8 @@ ###* -# @file Server stub +# @file Express server stub +# +# Start: +# $ ../../node_modules/coffee-script/bin/coffee server.coffee ### require 'coffee-script/register' @@ -9,6 +12,13 @@ express = require 'express' app = express() app.set 'port', process.env.PORT || 3333 +app.options '/machines', (req, res) -> + 'use strict' + allow = ['OPTIONS', 'HEAD', 'GET'] + res.setHeader 'Allow', allow.join ', ' + res.setHeader 'Cache-Control', 'no-cache, no-store, must-revalidate' + res.status(204).end() + app.get '/machines', (req, res) -> 'use strict' machine = From ba5e0ff3edd61204f50c47f71e3b591e97598737 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 28 Mar 2018 07:14:10 -0500 Subject: [PATCH 31/64] test(test/e2e/cli-test.coffee,test/fixtures/machines-get_head_options.raml): Verify correct handling Beefed up test to check both HEAD and OPTIONS responses. --- test/e2e/cli-test.coffee | 96 +++++++++++++++++--- test/fixtures/machines-get_head_options.raml | 59 ++++++++++++ 2 files changed, 143 insertions(+), 12 deletions(-) create mode 100644 test/fixtures/machines-get_head_options.raml diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index 20cbdc6..de4d5ce 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -353,19 +353,68 @@ describe 'Command line interface', () -> describe 'when executing the command and the server is responding as specified in the RAML', () -> - resTestTitle = 'GET /machines -> 200 Validate response code and body' + 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-single_get.raml" + ramlFile = "#{RAML_DIR}/machines-get_head_options.raml" cmd = "#{ABAO_BIN} #{ramlFile} --server #{SERVER} --reporter json" app = express() - app.get '/machines', (req, res) -> + 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'] + res.setHeader 'Allow', allow.join ', ' + res.setHeader 'Cache-Control', 'no-cache, no-store, must-revalidate' + res.status(204).end() + next() + + app.get '/machines', (req, res, next) -> machine = type: 'bulldozer' name: 'willy' 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' + ] + 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, () -> @@ -376,15 +425,39 @@ describe 'Command line interface', () -> before (done) -> runNormalTestAsync done - it 'should print count of tests run', () -> + 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(1) - expect(report.stats.passes).to.equal(1) + 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 'OPTIONS response should disable cacheing of it', () -> + cacheControl = optionsResponse.headers['Cache-Control'] + expect(cacheControl).to.equal('no-cache, no-store, must-revalidate') + + it 'OPTIONS and HEAD responses should not have bodies', () -> + expect(optionsResponse.body).to.be.empty + expect(headResponse.body).to.be.empty - it 'should print correct title for response', () -> - expect(report.tests).to.have.length(1) - expect(report.tests[0].fullTitle).to.equal(resTestTitle) + it 'GET and HEAD responses should have identical headers', () -> + expect(getResponse.headers).to.deep.equal(headResponse.headers) it 'should exit normally', () -> expect(exitStatus).to.equal(0) @@ -474,8 +547,7 @@ describe 'Command line interface', () -> app.use (req, res, next) -> err = null - produces = ["#{producedMediaType}"] - if !req.accepts produces + if !req.accepts ["#{producedMediaType}"] err = new Error('Not Acceptable') err.status = 406 next(err) @@ -484,7 +556,7 @@ describe 'Command line interface', () -> machine = type: 'bulldozer' name: 'willy' - res.setHeader 'Content-Type', "#{producedMediaType}" + res.type "#{producedMediaType}" res.status(200).send([machine]) app.use (err, req, res, next) -> 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 + From 1f9cf90860dd4a3e99e7c3a7e3cc1b20479eec40 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 28 Mar 2018 21:56:21 -0500 Subject: [PATCH 32/64] test(test/e2e/cli-test.coffee,test/stub/server.coffee): Remove spaces within Allow'd methods --- test/e2e/cli-test.coffee | 2 +- test/stub/server.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index de4d5ce..5e3943a 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -446,7 +446,7 @@ describe 'Command line interface', () -> it 'OPTIONS response should allow GET and HEAD requests', () -> allow = optionsResponse.headers['Allow'] - expect(allow).to.equal('OPTIONS, HEAD, GET') + expect(allow).to.equal('OPTIONS,HEAD,GET') it 'OPTIONS response should disable cacheing of it', () -> cacheControl = optionsResponse.headers['Cache-Control'] diff --git a/test/stub/server.coffee b/test/stub/server.coffee index 5fb52e5..f143d36 100644 --- a/test/stub/server.coffee +++ b/test/stub/server.coffee @@ -15,7 +15,7 @@ app.set 'port', process.env.PORT || 3333 app.options '/machines', (req, res) -> 'use strict' allow = ['OPTIONS', 'HEAD', 'GET'] - res.setHeader 'Allow', allow.join ', ' + res.setHeader 'Allow', allow.join ',' res.setHeader 'Cache-Control', 'no-cache, no-store, must-revalidate' res.status(204).end() From 5b51b37eb7c795cf3f93604b69d5c9cf7edb7792 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 28 Mar 2018 23:16:03 -0500 Subject: [PATCH 33/64] test(test/e2e/cli-test.coffee): Fix last commit Fixed Allow header join. Changed verbage of test description. --- test/e2e/cli-test.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index 5e3943a..5a41559 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -384,7 +384,7 @@ describe 'Command line interface', () -> app.options '/machines', (req, res, next) -> allow = ['OPTIONS', 'HEAD', 'GET'] - res.setHeader 'Allow', allow.join ', ' + res.setHeader 'Allow', allow.join ',' res.setHeader 'Cache-Control', 'no-cache, no-store, must-revalidate' res.status(204).end() next() @@ -456,7 +456,7 @@ describe 'Command line interface', () -> expect(optionsResponse.body).to.be.empty expect(headResponse.body).to.be.empty - it 'GET and HEAD responses should have identical headers', () -> + it 'GET and HEAD responses should have equivalent headers', () -> expect(getResponse.headers).to.deep.equal(headResponse.headers) it 'should exit normally', () -> From 4546e64924d2e750bc74ee3721519c85ff9896d6 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 2 Apr 2018 14:22:12 -0500 Subject: [PATCH 34/64] style(.travis.yml): Add spacing before environment values --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d3c2098..a03e19b 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= From 9e37eb8a35f7fe9dad57fa9fa356103690db8361 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 4 Apr 2018 07:13:05 -0500 Subject: [PATCH 35/64] fix(lib/test.coffee,test/unit/test-test.coffee): Remove unused banUnknown property Removed banUnknown property from tv4 exported module. Fixes: #237 --- lib/test.coffee | 9 ++++++--- test/unit/test-test.coffee | 4 ---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/test.coffee b/lib/test.coffee index 1dc65f3..43a2e3a 100644 --- a/lib/test.coffee +++ b/lib/test.coffee @@ -26,8 +26,6 @@ class TestFactory 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'))) @@ -120,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/test/unit/test-test.coffee b/test/unit/test-test.coffee index 54b4443..2f891f5 100644 --- a/test/unit/test-test.coffee +++ b/test/unit/test-test.coffee @@ -190,7 +190,6 @@ describe 'Test', () -> ) tv4Stub = {} - tv4Stub.banUnknown = false tv4Stub.addSchema = sinon.spy() TestTestFactory = proxyquire '../../lib/test', { @@ -203,7 +202,6 @@ 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', () -> @@ -211,7 +209,6 @@ describe 'Test', () -> assert.isTrue globStub.sync.calledWith 'thisisaword' assert.isTrue fsStub.readFileSync.calledOnce assert.isTrue fsStub.readFileSync.calledWith 'thisisaword', 'utf8' - assert.isTrue tv4Stub.banUnknown assert.isTrue tv4Stub.addSchema.calledWith(JSON.parse('{ "text": "example" }')) it 'test TestFactory with name 2', () -> @@ -219,7 +216,6 @@ describe 'Test', () -> assert.isTrue globStub.sync.calledWith 'thisIsAnotherWord' assert.isTrue fsStub.readFileSync.calledTwice assert.isTrue fsStub.readFileSync.calledWith 'thisIsAnotherWord', 'utf8' - assert.isTrue tv4Stub.banUnknown assert.isTrue tv4Stub.addSchema.calledWith(JSON.parse('{ "text": "example" }')) From 1f82b6f988fad4bab46d29151ddf0f21e18e41ed Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Sun, 8 Apr 2018 00:00:59 -0500 Subject: [PATCH 36/64] docs(README.md): Add issue submission instructions Added "npm" command which opens browser to project's GitHub issues. [ci skip] --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index fa719a8..aa988cb 100644 --- a/README.md +++ b/README.md @@ -276,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/ From e82c92135a3a1488fd13d0739db340939c836a94 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Sun, 8 Apr 2018 00:12:51 -0500 Subject: [PATCH 37/64] fix(lib/apply-configuration.coffee): Fix default option values Added default values for several missing options. Removed `reporters` which is handled by the CLI. --- lib/apply-configuration.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/apply-configuration.coffee b/lib/apply-configuration.coffee index 1e8082b..9fbf4ed 100644 --- a/lib/apply-configuration.coffee +++ b/lib/apply-configuration.coffee @@ -31,7 +31,9 @@ applyConfiguration = (config) -> options: server: null schemas: null - reporters: false + 'generate-hooks': false + template: null + timeout: 2000 reporter: null header: null names: false From ee0d49d4c8fa6c4ee5c6774e3184de21dd8344c8 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Sun, 8 Apr 2018 09:03:21 -0500 Subject: [PATCH 38/64] refactor(lib/apply-configuration.coffee,lib/test-runner.coffee): Migrate template file default setti Template file default was being set at invocation site, rather than in configuration. --- lib/apply-configuration.coffee | 7 ++++++- lib/test-runner.coffee | 6 +----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/apply-configuration.coffee b/lib/apply-configuration.coffee index 9fbf4ed..a945c48 100644 --- a/lib/apply-configuration.coffee +++ b/lib/apply-configuration.coffee @@ -2,6 +2,8 @@ # @file Stores command line arguments in configuration object ### +path = require 'path' + applyConfiguration = (config) -> 'use strict' @@ -47,7 +49,10 @@ applyConfiguration = (config) -> for own key, value of config configuration[key] = value - # Coerce some options into an dict + # 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 diff --git a/lib/test-runner.coffee b/lib/test-runner.coffee index 30b3530..7d57e51 100644 --- a/lib/test-runner.coffee +++ b/lib/test-runner.coffee @@ -95,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 From 4ce15568b5a4340bf8aec7b87da60dba755a11ce Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Sun, 8 Apr 2018 09:20:21 -0500 Subject: [PATCH 39/64] refactor(lib/cli.coffee): Reimplement code handling CLI option `--reporters` Existing code was literally copied from Mocha. Now instead of pretending to be Mocha, we tell Mocha to handle it. Little more awkward than hoped as option is handled within script rather than by its module export. --- lib/cli.coffee | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/lib/cli.coffee b/lib/cli.coffee index 61cb18c..f3ccde8 100644 --- a/lib/cli.coffee +++ b/lib/cli.coffee @@ -4,11 +4,12 @@ require 'coffee-script/register' +child_process = require 'child_process' path = require 'path' _ = require 'lodash' yargs = require 'yargs' -Abao = require '../lib/abao' +Abao = require './abao' pkg = require '../package' EXIT_SUCCESS = 0 @@ -16,22 +17,14 @@ EXIT_FAILURE = 1 showReporters = () -> 'use strict' - # 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() + 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 = [ From cfa716a4a45723fc762bf4974f857f875bd2abff Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Sun, 8 Apr 2018 12:13:36 -0500 Subject: [PATCH 40/64] refactor(lib/options.coffee): Reformat option descriptions Almost a style change (but involved code). Reformatted option descriptions to fit within 80 chars. Additionally, removed the variable and just exported the object itself. --- lib/options.coffee | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/options.coffee b/lib/options.coffee index 2fe565c..925d56f 100644 --- a/lib/options.coffee +++ b/lib/options.coffee @@ -2,7 +2,7 @@ # @file Command line options ### -options = +module.exports = 'generate-hooks': description: 'Output hooks generated from template file and exit' type: 'boolean' @@ -14,13 +14,15 @@ options = 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': @@ -49,11 +51,13 @@ options = 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: @@ -73,5 +77,3 @@ options = type: 'number' default: 2000 -module.exports = options - From 5ab8fe796d3ae45bc49a0d7316df63780d99772c Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 9 Apr 2018 04:05:48 -0500 Subject: [PATCH 41/64] test(test/e2e/cli-test.coffee): Tweak CacheControl response header value Removed spaces between response directives. Additionally, corrected misspelled 'cacheing'. --- test/e2e/cli-test.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index 5a41559..d8394a1 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -385,7 +385,8 @@ describe 'Command line interface', () -> app.options '/machines', (req, res, next) -> allow = ['OPTIONS', 'HEAD', 'GET'] res.setHeader 'Allow', allow.join ',' - res.setHeader 'Cache-Control', 'no-cache, no-store, must-revalidate' + disableCache = ['no-cache', 'no-store', 'must-revalidate'] + res.setHeader 'Cache-Control', disableCache.join ',' res.status(204).end() next() @@ -448,9 +449,9 @@ describe 'Command line interface', () -> allow = optionsResponse.headers['Allow'] expect(allow).to.equal('OPTIONS,HEAD,GET') - it 'OPTIONS response should disable cacheing of it', () -> + it 'OPTIONS response should disable caching of it', () -> cacheControl = optionsResponse.headers['Cache-Control'] - expect(cacheControl).to.equal('no-cache, no-store, must-revalidate') + expect(cacheControl).to.equal('no-cache,no-store,must-revalidate') it 'OPTIONS and HEAD responses should not have bodies', () -> expect(optionsResponse.body).to.be.empty From 97f702933c96ae2090f550d267feb9431a01e0ce Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 9 Apr 2018 04:35:34 -0500 Subject: [PATCH 42/64] test(test/e2e/cli-test.coffee): More fully disable HTTP caching in response Original code applied only to HTTP/1.1. Added two additional headers to handle HTTP/1.0, as well as proxies. --- test/e2e/cli-test.coffee | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index d8394a1..3677bba 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -387,6 +387,8 @@ describe 'Command line interface', () -> res.setHeader 'Allow', allow.join ',' disableCache = ['no-cache', 'no-store', 'must-revalidate'] res.setHeader 'Cache-Control', disableCache.join ',' + res.setHeader 'Pragma', disableCache[0] + res.setHeader 'Expires', '0' res.status(204).end() next() @@ -405,7 +407,9 @@ describe 'Command line interface', () -> if req.method == 'OPTIONS' return [ 'Allow', - 'Cache-Control' + 'Cache-Control', + 'Expires', + 'Pragma' ] else return [ @@ -452,6 +456,10 @@ describe 'Command line interface', () -> 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 From 61fbbf2885990edca1294da5a743993661e893c2 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 9 Apr 2018 07:36:49 -0500 Subject: [PATCH 43/64] test(test/e2e/cli-test.coffee,test/stub/server.coffee): More fully disable HTTP caching in response Added two additional headers to the stub code, missed in last commit. Made the e2e test match the stub's implementation. --- test/e2e/cli-test.coffee | 6 +++--- test/stub/server.coffee | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/test/e2e/cli-test.coffee b/test/e2e/cli-test.coffee index 3677bba..5b64cc5 100644 --- a/test/e2e/cli-test.coffee +++ b/test/e2e/cli-test.coffee @@ -384,10 +384,10 @@ describe 'Command line interface', () -> app.options '/machines', (req, res, next) -> allow = ['OPTIONS', 'HEAD', 'GET'] + directives = ['no-cache', 'no-store', 'must-revalidate'] res.setHeader 'Allow', allow.join ',' - disableCache = ['no-cache', 'no-store', 'must-revalidate'] - res.setHeader 'Cache-Control', disableCache.join ',' - res.setHeader 'Pragma', disableCache[0] + res.setHeader 'Cache-Control', directives.join ',' + res.setHeader 'Pragma', directives[0] res.setHeader 'Expires', '0' res.status(204).end() next() diff --git a/test/stub/server.coffee b/test/stub/server.coffee index f143d36..da69919 100644 --- a/test/stub/server.coffee +++ b/test/stub/server.coffee @@ -15,8 +15,11 @@ 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', 'no-cache, no-store, must-revalidate' + res.setHeader 'Cache-Control', directives.join ',' + res.setHeader 'Pragma', directives[0] + res.setHeader 'Expires', '0' res.status(204).end() app.get '/machines', (req, res) -> From 0990dc3fc2189b80c4ace06adb661b2cd9dffc9d Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 9 Apr 2018 18:04:33 -0500 Subject: [PATCH 44/64] build(.npmignore): Update .npmignore Add entries to eliminate unneded files in package artifact upon publication. [ci skip] --- .npmignore | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) 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 + From 89dcfed101d273b39c348f40dab170f7ef0fe049 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Mon, 9 Apr 2018 18:41:34 -0500 Subject: [PATCH 45/64] build(.gitignore): Update .gitignore Add entries to prevent undesired files from being added to SCCS. [ci ckip] --- .gitignore | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) 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 From 02682f9b130c7581b5e278847f85bceaab6de59c Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 00:39:49 -0500 Subject: [PATCH 46/64] refactor(bin/abao,lib/cli.coffee): Reduce CLI namespace litter Create main() to export from CLI. Code now executes main() function, with CLI options passed from binary. --- bin/abao | 3 +- lib/cli.coffee | 136 ++++++++++++++++++++++++++++--------------------- 2 files changed, 78 insertions(+), 61 deletions(-) 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/lib/cli.coffee b/lib/cli.coffee index f3ccde8..62f04ac 100644 --- a/lib/cli.coffee +++ b/lib/cli.coffee @@ -12,6 +12,14 @@ yargs = require 'yargs' Abao = require './abao' pkg = require '../package' +mochaOptionNames = [ + 'grep', + 'invert' + 'reporter', + 'reporters', + 'timeout' +] + EXIT_SUCCESS = 0 EXIT_FAILURE = 1 @@ -27,64 +35,74 @@ showReporters = () -> console.log stdout return -mochaOptionNames = [ - 'grep', - 'invert' - 'reporter', - 'timeout' -] -prog = path.basename pkg.bin - -argv = yargs - .usage("Usage:\n #{prog} [OPTIONS]" + - "\n\nExample:\n #{prog} api.raml --server http://api.example.com") - .options(Abao.options) - .group(mochaOptionNames, 'Options passed to Mocha:') - .implies('template', 'generate-hooks') - .check((argv) -> - 'use strict' - 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().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) -> +parseArgs = (argv) -> 'use strict' - 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() + 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(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 "#{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 + + ## TODO(plroebuck): Do all configuration in one place... + aliases = Object.keys(Abao.options).map (key) -> Abao.options[key].alias + .filter (val) -> val != undefined + alreadyHandled = [ + 'reporters', + 'help', + 'version' + ] + + configuration = + ramlPath: parsedArgs._[0], + options: _.omit parsedArgs, ['_', '$0', aliases..., alreadyHandled...] + + 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() + return # NOTREACHED + + +module.exports = + main: main From f4abe2c2da2d590690eb510abedaccaaa499e12d Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 01:14:58 -0500 Subject: [PATCH 47/64] test(test/unit/test-runner-test.coffee): Minor cleanup When resetting test objects, use `undefined` rather than empty string. Ensured test creation always performed in `before(done)`. Swapped order of restores in a couple `after` calls. --- test/unit/test-runner-test.coffee | 77 ++++++++++++++++--------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/test/unit/test-runner-test.coffee b/test/unit/test-runner-test.coffee index 3a1fcbd..4abbfd4 100644 --- a/test/unit/test-runner-test.coffee +++ b/test/unit/test-runner-test.coffee @@ -32,24 +32,25 @@ describe 'Test Runner', () -> 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' - ]""" + runner = undefined + beforeAllHook = undefined + afterAllHook = undefined + beforeHook = undefined + afterHook = undefined + runCallback = undefined before (done) -> + 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' + ]""" + options = server: "#{ABAO_IO_SERVER}" @@ -118,7 +119,7 @@ describe 'Test Runner', () -> hooksStub.runBefore.restore() hooksStub.runAfter.restore() - runCallback = '' + runCallback = undefined it 'should generate beforeAll hooks', () -> mochaStub = runner.mocha @@ -158,8 +159,8 @@ describe 'Test Runner', () -> describe 'Interact with #test', () -> - test = '' - runner = '' + test = undefined + runner = undefined before (done) -> testFactory = new TestFactory() @@ -320,7 +321,7 @@ describe 'Test Runner', () -> describe 'when test throws AssertionError', () -> - afterAllHook = '' + afterAllHook = undefined before (done) -> testFactory = new TestFactory() @@ -350,7 +351,7 @@ describe 'Test Runner', () -> done() after () -> - afterAllHook = '' + afterAllHook = undefined it 'should call afterAll hook', () -> afterAllHook.should.have.been.called @@ -358,8 +359,8 @@ describe 'Test Runner', () -> describe 'when beforeAllHooks throws UncaughtError', () -> - beforeAllHook = '' - afterAllHook = '' + beforeAllHook = undefined + afterAllHook = undefined before (done) -> testFactory = new TestFactory() @@ -392,8 +393,8 @@ describe 'Test Runner', () -> done() after () -> - beforeAllHook = '' - afterAllHook = '' + beforeAllHook = undefined + afterAllHook = undefined it 'should call afterAll hook', () -> afterAllHook.should.have.been.called @@ -431,8 +432,8 @@ describe 'Test Runner', () -> done() after () -> - runner.mocha.run.restore() console.log.restore() + runner.mocha.run.restore() it 'should not run mocha', () -> assert.notOk runner.mocha.run.called @@ -466,7 +467,7 @@ 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 @@ -483,17 +484,17 @@ 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) -> + 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 = {} + options = server: "#{SERVER}" 'hooks-only': true @@ -520,11 +521,11 @@ 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() it 'should run mocha', () -> assert.ok runner.mocha.run.called From 4d08d00615f0408bb74dd301349e579f230e2b49 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 02:16:33 -0500 Subject: [PATCH 48/64] build(package.json): Add support for "commitizen" and "husky" Had added everything for "commitizen" package some time back (except itself **face palm**). Added "husky" package, which provides Git pre-hooks, allowing *forced* test prior to commit. Changed "yargs" option to its actual value. Bumped package version (which should have been done a while back). --- package.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index fb2318a..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": { @@ -63,6 +65,7 @@ }, "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", @@ -76,6 +79,7 @@ "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", From 13f7fd6774dc5cad1af29533cb6e1a00ebec8682 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 02:41:57 -0500 Subject: [PATCH 49/64] test(test/unit/test-runner-test.coffee): Extract duplicate code into function Refactored a test creation function, now called by each test. Additionally, ensured reused variables would be reset to `undefined`. --- test/unit/test-runner-test.coffee | 88 ++++++++++++++----------------- 1 file changed, 39 insertions(+), 49 deletions(-) diff --git a/test/unit/test-runner-test.coffee b/test/unit/test-runner-test.coffee index 4abbfd4..efc3d05 100644 --- a/test/unit/test-runner-test.coffee +++ b/test/unit/test-runner-test.coffee @@ -27,12 +27,21 @@ 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 = undefined beforeAllHook = undefined afterAllHook = undefined beforeHook = undefined @@ -40,11 +49,7 @@ describe 'Test Runner', () -> runCallback = 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 = """[ type: 'string' @@ -120,6 +125,8 @@ describe 'Test Runner', () -> hooksStub.runAfter.restore() runCallback = undefined + runner = undefined + test = undefined it 'should generate beforeAll hooks', () -> mochaStub = runner.mocha @@ -159,15 +166,8 @@ describe 'Test Runner', () -> describe 'Interact with #test', () -> - test = undefined - runner = 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 = """[ type: 'string' @@ -190,6 +190,8 @@ describe 'Test Runner', () -> after () -> test.run.restore() + runner = undefined + test = undefined it 'should call #test.run', () -> assert.ok test.run.calledOnce @@ -219,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 @@ -237,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' @@ -264,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 @@ -282,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 = @@ -304,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 @@ -324,11 +324,7 @@ describe 'Test Runner', () -> 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() @@ -352,6 +348,8 @@ describe 'Test Runner', () -> after () -> afterAllHook = undefined + runner = undefined + test = undefined it 'should call afterAll hook', () -> afterAllHook.should.have.been.called @@ -363,11 +361,7 @@ describe 'Test Runner', () -> 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() @@ -395,6 +389,8 @@ describe 'Test Runner', () -> after () -> beforeAllHook = undefined afterAllHook = undefined + runner = undefined + test = undefined it 'should call afterAll hook', () -> afterAllHook.should.have.been.called @@ -405,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' @@ -434,6 +426,8 @@ describe 'Test Runner', () -> after () -> console.log.restore() runner.mocha.run.restore() + runner = undefined + test = undefined it 'should not run mocha', () -> assert.notOk runner.mocha.run.called @@ -448,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 = {} @@ -474,6 +464,8 @@ describe 'Test Runner', () -> after () -> runner.mocha.run.restore() + runner = undefined + test = undefined it 'should run mocha', () -> assert.ok runner.mocha.run.called @@ -487,11 +479,7 @@ describe 'Test Runner', () -> suiteStub = 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 = {} @@ -526,6 +514,8 @@ describe 'Test Runner', () -> 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 From 5d1f08b9d74a2b6d7e2f892b278325249ef84acb Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 04:24:02 -0500 Subject: [PATCH 50/64] refactor(lib/configuration.coffee,lib/abao.coffee,test/unit/abao-test.coffee): Rename 'apply-configu Preparing to change how configuration will work going forward. Renamed file itself, and in the abao `require`. Removed from test code as unused. --- lib/abao.coffee | 4 ++-- lib/{apply-configuration.coffee => configuration.coffee} | 0 test/unit/abao-test.coffee | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) rename lib/{apply-configuration.coffee => configuration.coffee} (100%) diff --git a/lib/abao.coffee b/lib/abao.coffee index ff746c0..a675c8b 100644 --- a/lib/abao.coffee +++ b/lib/abao.coffee @@ -8,7 +8,7 @@ ramlParser = require 'raml-parser' addTests = require './add-tests' addHooks = require './add-hooks' -applyConfiguration = require './apply-configuration' +applyConfiguration = require './configuration' hooks = require './hooks' options = require './options' Runner = require './test-runner' @@ -18,7 +18,7 @@ TestFactory = require './test' class Abao constructor: (config) -> 'use strict' - @configuration = applyConfiguration(config) + @configuration = applyConfiguration config @tests = [] @hooks = hooks diff --git a/lib/apply-configuration.coffee b/lib/configuration.coffee similarity index 100% rename from lib/apply-configuration.coffee rename to lib/configuration.coffee diff --git a/test/unit/abao-test.coffee b/test/unit/abao-test.coffee index c8a3124..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 } From f28ceafc0835231b035ee620e6a9cc682b20b03c Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 05:23:57 -0500 Subject: [PATCH 51/64] refactor(lib/abao.coffee,lib/cli.coffee): Remove `Abao.options` export Eliminated unnecessary export of cmdline options. --- lib/abao.coffee | 2 -- lib/cli.coffee | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/abao.coffee b/lib/abao.coffee index a675c8b..c73a822 100644 --- a/lib/abao.coffee +++ b/lib/abao.coffee @@ -10,7 +10,6 @@ addTests = require './add-tests' addHooks = require './add-hooks' applyConfiguration = require './configuration' hooks = require './hooks' -options = require './options' Runner = require './test-runner' TestFactory = require './test' @@ -59,5 +58,4 @@ class Abao module.exports = Abao -module.exports.options = options diff --git a/lib/cli.coffee b/lib/cli.coffee index 62f04ac..a4819e2 100644 --- a/lib/cli.coffee +++ b/lib/cli.coffee @@ -10,6 +10,7 @@ _ = require 'lodash' yargs = require 'yargs' Abao = require './abao' +allOptions = require './options' pkg = require '../package' mochaOptionNames = [ @@ -41,7 +42,7 @@ parseArgs = (argv) -> return yargs(argv) .usage("Usage:\n #{prog} [OPTIONS]" + "\n\nExample:\n #{prog} api.raml --server http://api.example.com") - .options(Abao.options) + .options(allOptions) .group(mochaOptionNames, 'Options passed to Mocha:') .implies('template', 'generate-hooks') .check((argv) -> @@ -71,7 +72,7 @@ main = (argv) -> parsedArgs = parseArgs argv ## TODO(plroebuck): Do all configuration in one place... - aliases = Object.keys(Abao.options).map (key) -> Abao.options[key].alias + aliases = Object.keys(allOptions).map (key) -> allOptions[key].alias .filter (val) -> val != undefined alreadyHandled = [ 'reporters', From 3ee9f5f1258d9f2d9266d1d35370a9091257f207 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 06:05:04 -0500 Subject: [PATCH 52/64] refactor(lib/abao.coffee,lib/cli.coffee,lib/configuration.coffee): Migrate all configuration into si Completed first phase of getting all configuration into single file. --- lib/abao.coffee | 11 ++++++++--- lib/cli.coffee | 34 ++++++++-------------------------- lib/configuration.coffee | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/lib/abao.coffee b/lib/abao.coffee index c73a822..430dbed 100644 --- a/lib/abao.coffee +++ b/lib/abao.coffee @@ -8,16 +8,21 @@ ramlParser = require 'raml-parser' addTests = require './add-tests' addHooks = require './add-hooks' -applyConfiguration = require './configuration' +asConfiguration = require './configuration' hooks = require './hooks' Runner = require './test-runner' TestFactory = require './test' +defaultArgs = + _: [] + options: + help: true + class Abao - constructor: (config) -> + constructor: (parsedArgs = defaultArgs) -> 'use strict' - @configuration = applyConfiguration config + @configuration = asConfiguration parsedArgs @tests = [] @hooks = hooks diff --git a/lib/cli.coffee b/lib/cli.coffee index a4819e2..c1082f7 100644 --- a/lib/cli.coffee +++ b/lib/cli.coffee @@ -13,14 +13,6 @@ Abao = require './abao' allOptions = require './options' pkg = require '../package' -mochaOptionNames = [ - 'grep', - 'invert' - 'reporter', - 'reporters', - 'timeout' -] - EXIT_SUCCESS = 0 EXIT_FAILURE = 1 @@ -38,6 +30,13 @@ showReporters = () -> parseArgs = (argv) -> 'use strict' + mochaOptionNames = [ + 'grep', + 'invert' + 'reporter', + 'reporters', + 'timeout' + ] prog = path.basename pkg.bin return yargs(argv) .usage("Usage:\n #{prog} [OPTIONS]" + @@ -71,24 +70,7 @@ main = (argv) -> 'use strict' parsedArgs = parseArgs argv - ## 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...] - - mochaOptions = _.pick configuration.options, mochaOptionNames - configuration.options = _.omit configuration.options, mochaOptionNames - configuration.options.mocha = mochaOptions - - abao = new Abao configuration + abao = new Abao parsedArgs abao.run (error, nfailures) -> if error process.exitCode = EXIT_FAILURE diff --git a/lib/configuration.coffee b/lib/configuration.coffee index a945c48..eade891 100644 --- a/lib/configuration.coffee +++ b/lib/configuration.coffee @@ -2,8 +2,12 @@ # @file Stores command line arguments in configuration object ### +_ = require 'lodash' path = require 'path' +allOptions = require './options' + + applyConfiguration = (config) -> 'use strict' @@ -62,5 +66,34 @@ applyConfiguration = (config) -> return configuration -module.exports = applyConfiguration +asConfiguration = (parsedArgs) -> + ## 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 = [ + 'grep', + 'invert' + 'reporter', + 'reporters', + 'timeout' + ] + + mochaOptions = _.pick configuration.options, mochaOptionNames + configuration.options = _.omit configuration.options, mochaOptionNames + configuration.options.mocha = mochaOptions + + return applyConfiguration config + + +module.exports = asConfiguration From 6331ff3bd774ef14124e4a109949f7ca73438f1b Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 06:11:47 -0500 Subject: [PATCH 53/64] fix(lib/configuration.coffee): Fix for previous commit Corrected variable name. --- lib/configuration.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/configuration.coffee b/lib/configuration.coffee index eade891..dfcf570 100644 --- a/lib/configuration.coffee +++ b/lib/configuration.coffee @@ -92,7 +92,7 @@ asConfiguration = (parsedArgs) -> configuration.options = _.omit configuration.options, mochaOptionNames configuration.options.mocha = mochaOptions - return applyConfiguration config + return applyConfiguration configuration module.exports = asConfiguration From 23f15c1f5cf6879206080ee48c34720c98cf7755 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 07:36:53 -0500 Subject: [PATCH 54/64] refactor(lib/options-abao.coffee,lib/options-mocha.coffee,lib/cli.coffee,lib/configuration.coffee): Split options according to who used them. This should complete second phase of three for configuration. --- lib/cli.coffee | 12 +++----- lib/configuration.coffee | 21 ++++++-------- lib/{options.coffee => options-abao.coffee} | 0 lib/options-mocha.coffee | 31 +++++++++++++++++++++ 4 files changed, 44 insertions(+), 20 deletions(-) rename lib/{options.coffee => options-abao.coffee} (100%) create mode 100644 lib/options-mocha.coffee diff --git a/lib/cli.coffee b/lib/cli.coffee index c1082f7..3fd9275 100644 --- a/lib/cli.coffee +++ b/lib/cli.coffee @@ -10,7 +10,8 @@ _ = require 'lodash' yargs = require 'yargs' Abao = require './abao' -allOptions = require './options' +abaoOptions = require './options-abao' +mochaOptions = require './options-mocha' pkg = require '../package' EXIT_SUCCESS = 0 @@ -30,13 +31,8 @@ showReporters = () -> parseArgs = (argv) -> 'use strict' - mochaOptionNames = [ - 'grep', - 'invert' - 'reporter', - 'reporters', - 'timeout' - ] + allOptions = _.assign {}, abaoOptions, mochaOptions + mochaOptionNames = Object.keys mochaOptions prog = path.basename pkg.bin return yargs(argv) .usage("Usage:\n #{prog} [OPTIONS]" + diff --git a/lib/configuration.coffee b/lib/configuration.coffee index dfcf570..1977c16 100644 --- a/lib/configuration.coffee +++ b/lib/configuration.coffee @@ -5,7 +5,9 @@ _ = require 'lodash' path = require 'path' -allOptions = require './options' +abaoOptions = require './options-abao' +mochaOptions = require './options-mocha' +allOptions = _.assign {}, abaoOptions, mochaOptions applyConfiguration = (config) -> @@ -65,7 +67,9 @@ applyConfiguration = (config) -> return configuration - +# Create configuration settings from CLI arguments applied against options +# @param {Object} parsedArgs - yargs .argv() output +# @returns {Object} configuration object asConfiguration = (parsedArgs) -> ## TODO(plroebuck): Do all configuration in one place... aliases = Object.keys(allOptions).map (key) -> allOptions[key].alias @@ -80,17 +84,10 @@ asConfiguration = (parsedArgs) -> ramlPath: parsedArgs._[0], options: _.omit parsedArgs, ['_', '$0', aliases..., alreadyHandled...] - mochaOptionNames = [ - 'grep', - 'invert' - 'reporter', - 'reporters', - 'timeout' - ] - - mochaOptions = _.pick configuration.options, mochaOptionNames + mochaOptionNames = Object.keys mochaOptions + optionsToReparent = _.pick configuration.options, mochaOptionNames configuration.options = _.omit configuration.options, mochaOptionNames - configuration.options.mocha = mochaOptions + configuration.options.mocha = optionsToReparent return applyConfiguration configuration diff --git a/lib/options.coffee b/lib/options-abao.coffee similarity index 100% rename from lib/options.coffee rename to lib/options-abao.coffee 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 + From 648bed23926b5ddc90e00080da96bd206707373c Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 07:42:40 -0500 Subject: [PATCH 55/64] fix(lib/options-abao.coffee): Fix for previous commit Last commit renamed the file, but left out changes to remove Mocha options. --- lib/options-abao.coffee | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/lib/options-abao.coffee b/lib/options-abao.coffee index 925d56f..62b51a6 100644 --- a/lib/options-abao.coffee +++ b/lib/options-abao.coffee @@ -1,5 +1,5 @@ ###* -# @file Command line options +# @file Command line options (Abao-related) ### module.exports = @@ -7,11 +7,6 @@ module.exports = 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 ' + @@ -30,26 +25,11 @@ module.exports = 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' @@ -71,9 +51,3 @@ module.exports = type: 'string' normalize: true - timeout: - alias: 't' - description: 'Set test case timeout in milliseconds' - type: 'number' - default: 2000 - From 970c63673a33115a78e6c2d10360a2b818712988 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 12:25:55 -0500 Subject: [PATCH 56/64] ci(.travis.yml): [TEST] Get Environment Listing --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a03e19b..7825c61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,5 +32,6 @@ after_success: - PROJ_COVER_DIR="$PROJ_BUILD_DIR/coverage" - COVERAGE_FILE="$PROJ_COVER_DIR/coverage.lcov" - COVERALLS_BIN="./node_modules/coveralls/bin/coveralls.js" + - env | sort - $COVERALLS_BIN lib < $COVERAGE_FILE; echo "exit=$?" From 55e59d6915d847e79a8360126552b365f8a3d232 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 12:35:08 -0500 Subject: [PATCH 57/64] ci(.travis.yml): [TEST] Get Environment Listing (redux) --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7825c61..5e5bf3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,12 +26,12 @@ 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" + - export BUILD_DIR="$HOME/build" + - export GITHUB_REPO="cybertk/abao" + - export PROJ_BUILD_DIR="$BUILD_DIR/$TRAVIS_REPO_SLUG" + - export PROJ_COVER_DIR="$PROJ_BUILD_DIR/coverage" + - export COVERAGE_FILE="$PROJ_COVER_DIR/coverage.lcov" + - export COVERALLS_BIN="./node_modules/coveralls/bin/coveralls.js" - env | sort - $COVERALLS_BIN lib < $COVERAGE_FILE; echo "exit=$?" From 1adc4572947e1ed0bd2871cb3eeed4471b499930 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 13:55:45 -0500 Subject: [PATCH 58/64] ci(.travis.yml): [TEST] Display build info Debug why `npm publish` has not been occurring. --- .travis.yml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5e5bf3e..2c9ac7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,11 @@ node_js: - '4' env: - NODE_ENV=development + global: + # Get all branches referencing this commit + - REAL_BRANCH=$(git ls-remote origin | sed -n "\|$TRAVIS_COMMIT\s\+refs/heads/|{s///p}") + # Check if we are on a particular branch: + - IS_RELEASE=$(git ls-remote origin | grep "$TRAVIS_COMMIT\s\+refs/heads/release$") notifications: slack: secure: fsCX0/TDE9TAJR0S91dboOZ4expmCc8o6joVzsHNJYTJfDtSJehdKjTzYuO/vsRigOOoQZ0dJEPl+D4fysBDV+jkOT5sTjp/uKtcfwHwPi03K8GauwvyW0x4N1M+mY+5jN2ZyBZXqVM5dc0wbgldP9QOg5UpB80hfWUZ+0F1MTM= @@ -26,12 +31,20 @@ deploy: repo: cybertk/abao after_success: # - grunt coveralls:upload - - export BUILD_DIR="$HOME/build" - - export GITHUB_REPO="cybertk/abao" - - export PROJ_BUILD_DIR="$BUILD_DIR/$TRAVIS_REPO_SLUG" - - export PROJ_COVER_DIR="$PROJ_BUILD_DIR/coverage" - - export COVERAGE_FILE="$PROJ_COVER_DIR/coverage.lcov" - - export COVERALLS_BIN="./node_modules/coveralls/bin/coveralls.js" - - env | sort + - 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 "REAL_BRANCH=$REAL_BRANCH" + - echo "IS_RELEASE=$IS_RELEASE" + - echo "===== BUILD =====" + - echo "TRAVIS_BUILD_NUMBER=$TRAVIS_BUILD_NUMBER" + - echo "TRAVIS_BUILD_DIR=$TRAVIS_BUILD_DIR" From 8e30c7d3ac7480853e403f4a4ee538df3263613a Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 14:38:30 -0500 Subject: [PATCH 59/64] fix(configuration.coffee): Fix lint warning Added missing 'use strict' to `asConfiguration()`. --- lib/configuration.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/configuration.coffee b/lib/configuration.coffee index 1977c16..4ac93fc 100644 --- a/lib/configuration.coffee +++ b/lib/configuration.coffee @@ -71,6 +71,7 @@ applyConfiguration = (config) -> # @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 From 9d8d865690d6d4c0eb0056e9221a33fa550de27a Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 14:44:31 -0500 Subject: [PATCH 60/64] ci(.travis.yml): Fix parsing error --- .travis.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2c9ac7a..6bf4916 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,11 +13,6 @@ node_js: - '4' env: - NODE_ENV=development - global: - # Get all branches referencing this commit - - REAL_BRANCH=$(git ls-remote origin | sed -n "\|$TRAVIS_COMMIT\s\+refs/heads/|{s///p}") - # Check if we are on a particular branch: - - IS_RELEASE=$(git ls-remote origin | grep "$TRAVIS_COMMIT\s\+refs/heads/release$") notifications: slack: secure: fsCX0/TDE9TAJR0S91dboOZ4expmCc8o6joVzsHNJYTJfDtSJehdKjTzYuO/vsRigOOoQZ0dJEPl+D4fysBDV+jkOT5sTjp/uKtcfwHwPi03K8GauwvyW0x4N1M+mY+5jN2ZyBZXqVM5dc0wbgldP9QOg5UpB80hfWUZ+0F1MTM= @@ -42,8 +37,6 @@ after_success: - echo "TRAVIS_COMMIT_MESSAGE=$TRAVIS_COMMIT_MESSAGE" - echo "TRAVIS_TAG=$TRAVIS_TAG" - echo "TRAVIS_BRANCH=$TRAVIS_BRANCH" - - echo "REAL_BRANCH=$REAL_BRANCH" - - echo "IS_RELEASE=$IS_RELEASE" - echo "===== BUILD =====" - echo "TRAVIS_BUILD_NUMBER=$TRAVIS_BUILD_NUMBER" - echo "TRAVIS_BUILD_DIR=$TRAVIS_BUILD_DIR" From fc6736cc1f5a1bca5f2f13211a214a454b204f87 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 15:52:54 -0500 Subject: [PATCH 61/64] refactor(lib/abao.coffee): Refactor async.waterfall() Simplified understanding waterfall steps. Added error handling to loading RAML step. Noted shortcoming in current `addHooks()` handling. --- lib/abao.coffee | 62 ++++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/lib/abao.coffee b/lib/abao.coffee index 430dbed..be05feb 100644 --- a/lib/abao.coffee +++ b/lib/abao.coffee @@ -32,33 +32,47 @@ class Abao tests = @tests hooks = @hooks - # Inject the JSON refs schemas - factory = new TestFactory(config.options.schemas) + parseHooks = (callback) -> +# TODO(plroebuck): addHooks should be using callback. Convert to use below... +# addHooks hooks, config.options.hookfiles, callback +# return # NOTREACHED + addHooks hooks, config.options.hookfiles + return callback() + + loadRAML = (callback) -> + if !config.ramlPath + return callback(new Error 'unspecified RAML file') + + 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 From 7d988645d8720b03f37c30ac435626374caa9ab5 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Tue, 10 Apr 2018 21:10:16 -0500 Subject: [PATCH 62/64] feat(lib/add-hooks.coffee,lib/abao.coffee,test/unit/add-hooks-test.coffee): Revamp `addHooks()` to u Significant rewrite with more error checking. Updated associated tests and invocation. --- lib/abao.coffee | 7 +- lib/add-hooks.coffee | 26 ++-- test/unit/add-hooks-test.coffee | 203 ++++++++++++++++++++++---------- 3 files changed, 159 insertions(+), 77 deletions(-) diff --git a/lib/abao.coffee b/lib/abao.coffee index be05feb..3eee70f 100644 --- a/lib/abao.coffee +++ b/lib/abao.coffee @@ -33,11 +33,8 @@ class Abao hooks = @hooks parseHooks = (callback) -> -# TODO(plroebuck): addHooks should be using callback. Convert to use below... -# addHooks hooks, config.options.hookfiles, callback -# return # NOTREACHED - addHooks hooks, config.options.hookfiles - return callback() + addHooks hooks, config.options.hookfiles, callback + return # NOTREACHED loadRAML = (callback) -> if !config.ramlPath diff --git a/lib/add-hooks.coffee b/lib/add-hooks.coffee index 25c7efe..32320cf 100644 --- a/lib/add-hooks.coffee +++ b/lib/add-hooks.coffee @@ -8,27 +8,29 @@ 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/test/unit/add-hooks-test.coffee b/test/unit/add-hooks-test.coffee index ef32ab1..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,97 +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() From 19eb224920524ded1e50f2ab2c2f1038ce9b9aa0 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 11 Apr 2018 07:26:24 -0500 Subject: [PATCH 63/64] style(lib/abao.coffee): Reformat to be more CoffeeScript-like Removed unnecessary parentheses. --- lib/abao.coffee | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/abao.coffee b/lib/abao.coffee index 3eee70f..fa03def 100644 --- a/lib/abao.coffee +++ b/lib/abao.coffee @@ -38,13 +38,14 @@ class Abao loadRAML = (callback) -> if !config.ramlPath - return callback(new Error 'unspecified RAML file') + nofile = new Error 'unspecified RAML file' + return callback nofile - ramlParser.loadFile(config.ramlPath) + ramlParser.loadFile config.ramlPath .then (raml) -> - return callback(null, raml) + return callback null, raml .catch (err) -> - return callback(err) + return callback err return # NOTREACHED parseTestsFromRAML = (raml, callback) -> @@ -53,7 +54,7 @@ class Abao config.options.server = raml.baseUri # Inject the JSON refs schemas - factory = new TestFactory(config.options.schemas) + factory = new TestFactory config.options.schemas addTests raml, tests, hooks, callback, factory, config.options.sorted return # NOTREACHED From 0cb0335a71ac0eb2bb9e4c8a2d0f53b5d77f7ead Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 11 Apr 2018 08:13:49 -0500 Subject: [PATCH 64/64] chore(.editorconfig): Add EditorConfig file [ci skip] --- .editorconfig | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .editorconfig 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 +