Skip to content

Commit

Permalink
Merge pull request #119 from cybertk/generate_hooks
Browse files Browse the repository at this point in the history
Generate hooks
  • Loading branch information
plroebuck committed Apr 6, 2016
2 parents 1faab22 + 83932c3 commit 3313346
Show file tree
Hide file tree
Showing 15 changed files with 420 additions and 211 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,16 @@ $ abao single-get.raml --names
GET /machines -> 200
```

Write a hookfile in *JavaScript* named `test_machines_hooks.js`:
**Abao** can generate a hookfile to help validate more than just the
response code for each path.

```bash
$ abao single-get.raml --generate-hooks > test_machines_hooks.js

```

Then edit the *JavaScript* hookfile `test_machines_hooks.js` created in the
previous step to add request parameters and response validation logic.

```js
var hooks = require('hooks'),
Expand Down
3 changes: 2 additions & 1 deletion bin/abao
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var argv = yargs
.usage("Usage:\n abao </path/to/raml> [OPTIONS]" +
"\n\nExample:\n " + "abao api.raml --server http://api.example.com")
.options(Abao.options)
.wrap(80)
.implies('template', 'generate-hooks')
.check(function (argv) {
if (argv.reporters === true) {
showReporters();
Expand All @@ -26,6 +26,7 @@ var argv = yargs

return true;
})
.wrap(80)
.help('help', 'Show usage information and exit')
.version().describe('version', 'Show version number and exit')
.epilog("Website:\n " + 'https://github.com/cybertk/abao')
Expand Down
8 changes: 4 additions & 4 deletions lib/abao.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
sms = require("source-map-support").install({handleUncaughtExceptions: false})
raml = require 'raml-parser'
ramlParser = require 'raml-parser'
async = require 'async'

options = require './options'
Expand All @@ -22,7 +22,7 @@ class Abao
tests = @tests
hooks = @hooks

# init the test factory to inject the json refs schemas
# Inject the JSON refs schemas
factory = new TestFactory(config.options.schemas)

async.waterfall [
Expand All @@ -33,7 +33,7 @@ class Abao
,
# Load RAML
(callback) ->
raml.loadFile(config.ramlPath).then (raml) ->
ramlParser.loadFile(config.ramlPath).then (raml) ->
callback(null, raml)
, callback
,
Expand All @@ -46,7 +46,7 @@ class Abao
,
# Run tests
(callback) ->
runner = new Runner config.options
runner = new Runner config.options, config.ramlPath
runner.run tests, hooks, callback
], done

Expand Down
3 changes: 1 addition & 2 deletions lib/add-hooks.coffee
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
path = require 'path'

require 'coffee-script/register'
proxyquire = require('proxyquire').noCallThru()
glob = require 'glob'
path = require 'path'


addHooks = (hooks, pattern) ->
Expand Down
1 change: 1 addition & 0 deletions lib/add-tests.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ async = require 'async'
_ = require 'underscore'
csonschema = require 'csonschema'


parseSchema = (source) ->
if source.contains('$schema')
#jsonschema
Expand Down
5 changes: 2 additions & 3 deletions lib/apply-configuration.coffee
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

applyConfiguration = (config) ->

coerceToArray = (value) ->
Expand Down Expand Up @@ -35,11 +34,11 @@ applyConfiguration = (config) ->
invert: false
'hooks-only': false

# normalize options and config
# Normalize options and config
for own key, value of config
configuration[key] = value

# coerce some options into an dict
# Coerce some options into an dict
configuration.options.header = coerceToDict(configuration.options.header)

# TODO(quanlong): OAuth2 Bearer Token
Expand Down
30 changes: 30 additions & 0 deletions lib/generate-hooks.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
fs = require 'fs'
Mustache = require 'mustache'

generateHooks = (names, ramlFile, templateFile, callback) ->
if !names
callback new Error 'no names found for which to generate hooks'

if !templateFile
callback new Error 'missing template file'

try
template = fs.readFileSync templateFile, 'utf8'
datetime = new Date().toISOString().replace('T', ' ').substr(0, 19)
view =
ramlFile: ramlFile
timestamp: datetime
hooks:
{ 'name': name } for name in names
view.hooks[0].comment = true

content = Mustache.render template, view
console.log content
catch error
console.error 'failed to generate skeleton hooks'
callback error

callback

module.exports = generateHooks

1 change: 1 addition & 0 deletions lib/hooks.coffee
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
async = require 'async'
_ = require 'underscore'


class Hooks
constructor: () ->
@beforeHooks = {}
Expand Down
19 changes: 14 additions & 5 deletions lib/options.coffee
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
options =
server:
description: 'Specify the 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'

hookfiles:
alias: 'f'
description: 'Specify a 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'

schemas:
alias: 's'
description: 'Specify a 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'

reporter:
alias: 'r'
description: 'Specify the reporter to use'
description: 'Specify reporter to use'
type: 'string'
default: 'spec'

header:
alias: 'h'
description: 'Add header to include in each request. The header must be in KEY:VALUE format, e.g. "-h Accept:application/json".\nReuse 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'

'hooks-only':
Expand All @@ -45,11 +45,20 @@ options =
type: 'number'
default: 2000

template:
description: 'Specify template file to use for generating hooks'
type: 'string'
normalize: true

names:
alias: 'n'
description: 'List names of requests and exit'
type: 'boolean'

'generate-hooks':
description: 'Output hooks generated from template file and exit'
type: 'boolean'

reporters:
description: 'Display available reporters and exit'
type: 'boolean'
Expand Down
1 change: 1 addition & 0 deletions lib/server.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
express = require 'express'


PORT = '3333'

app = express()
Expand Down
48 changes: 35 additions & 13 deletions lib/test-runner.coffee
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
Mocha = require 'mocha'
Mustache = require 'mustache'
async = require 'async'
path = require 'path'
_ = require 'underscore'
generateHooks = require './generate-hooks'


class TestRunner
constructor: (options) ->
constructor: (options, ramlFile) ->
@server = options.server
delete options.server
@options = options
@mocha = new Mocha options
@ramlFile = ramlFile

addTestToMocha: (test, hooks) =>
mocha = @mocha
Expand Down Expand Up @@ -39,39 +43,57 @@ class TestRunner

# Setup test
# Vote test name
title = if test.response.schema then 'Validate response code and body' else 'Validate response code only'
title = if test.response.schema
'Validate response code and body'
else
'Validate response code only'
suite.addTest new Mocha.Test title, _.bind (done) ->
@test.run done
, {test}

run: (tests, hooks, callback) ->
run: (tests, hooks, done) ->
server = @server
options = @options
addTestToMocha = @addTestToMocha
mocha = @mocha
ramlFile = path.basename @ramlFile
names = []

async.waterfall [
(callback) ->
async.each tests, (test, done) ->
# list tests
if options.names
console.log test.name
return done()
async.each tests, (test, cb) ->
if options.names || options['generate-hooks']
# Save test names for use by next step
names.push test.name
return cb()

# none shall pass without...
# None shall pass without...
return callback(new Error 'no API endpoint specified') if !server

# Update test.request
test.request.server = server
_.extend(test.request.headers, options.header)

addTestToMocha test, hooks
done()
cb()
, callback
, # Handle options that don't run tests
(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
else if options.names
# Write names to console
console.log name for name in names
return done(null, 0)
else
return callback()
, # Run mocha
(callback) ->
return callback(null, 0) if options.names

mocha.suite.beforeAll _.bind (done) ->
@hooks.runBeforeAll done
, {hooks}
Expand All @@ -81,7 +103,7 @@ class TestRunner

mocha.run (failures) ->
callback(null, failures)
], callback
], done


module.exports = TestRunner
Expand Down
3 changes: 3 additions & 0 deletions lib/test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ glob = require 'glob'

assert = chai.assert


String::contains = (it) ->
@indexOf(it) != -1


class TestFactory
constructor: (schemaLocation) ->
if schemaLocation
Expand All @@ -27,6 +29,7 @@ class TestFactory
create: (name, contentTest) ->
return new Test(name, contentTest)


class Test
constructor: (@name, @contentTest) ->
@name ?= ''
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "abao",
"version": "0.4.0-beta.6",
"version": "0.4.0-beta.7",
"description": "RAML testing tool",
"bin": "bin/abao",
"main": "lib/index.js",
Expand Down Expand Up @@ -55,6 +55,7 @@
"glob": "^7.0.3",
"jsonlint": "^1.6.2",
"mocha": "~2.4.5",
"mustache": "~2.2.1",
"proxyquire": "^1.3.1",
"raml-parser": "^0.8.16",
"request": "^2.53.0",
Expand Down
47 changes: 47 additions & 0 deletions templates/hookfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// ABAO hooks file {{! Mustache template }}
// Generated from RAML specification
// RAML: {{ramlFile}}
// Date: {{timestamp}}
// <https://github.com/cybertk/abao>
//

var
hooks = require('hooks'),
assert = require('chai').assert;

//
// Setup/Teardown
//

hooks.beforeAll(function (done) {
done();
});

hooks.afterAll(function (done) {
done();
});


//
// Hooks
//

{{#hooks}}
//-----------------------------------------------------------------------------
hooks.before('{{{name}}}', function (test, done) {
{{#comment}}
// Modify 'test.request' properties here to modify the inbound request
{{/comment}}
done();
});

hooks.after('{{{name}}}', function (test, done) {
{{#comment}}
// Assert against 'test.response' properties here to verify expected results
{{/comment}}
done();
});

{{/hooks}}

Loading

0 comments on commit 3313346

Please sign in to comment.