Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

api-test

Package Overview
Dependencies
Maintainers
1
Versions
48
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

api-test - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

array-sintax.md

68

baseContext.js

@@ -6,13 +6,59 @@ /**

var crypto = require('crypto')
var ObjectID = require('mongodb').ObjectID
module.exports = {
randomId: function () {
return crypto.pseudoRandomBytes(12).toString('hex')
},
randomStr: function (len) {
len = len || 7
return crypto.pseudoRandomBytes(Math.ceil(len * 3 / 4)).toString('base64').substr(0, len)
},
empty: {}
}
/**
* Generate a random mongo objectId
* @returns {string}
*/
module.exports.randomId = function () {
return new ObjectID().toHexString()
}
/**
* Generate a random string with base64 chars (A-Za-z0-9+/)
* @param {number} [len=7]
* @param {string} [alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/']
* @returns {string}
*/
module.exports.randomStr = function (len, alphabet) {
var i, str = ''
len = len || 7
alphabet = alphabet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
for (i = 0; i < len; i++) {
str += alphabet[Math.floor(Math.random() * alphabet.length)]
}
return str
}
/**
* Generate a random string with hex chars (0-9a-f)
* @param {number} [len=7]
* @returns {string}
*/
module.exports.randomHex = function (len) {
return module.exports.randomStr(len, '0123456789abcdef')
}
/**
* Generate a random string with digits (0-9)
* @param {number} [len=7]
* @returns {string}
*/
module.exports.randomCode = function (len) {
return module.exports.randomStr(len, '0123456789')
}
/**
* Generate a random valid email address
* @param {string} [domain='example.com']
* @returns {string}
*/
module.exports.randomEmail = function (domain) {
domain = domain || 'example.com'
return 'test-' + module.exports.randomId() + '@' + domain
}
/**
* The empty object
*/
module.exports.empty = {}

10

Case.js

@@ -13,8 +13,10 @@ 'use strict'

* @property {Object} out
* @property {number} statusCode
* @property {Find[]} finds
*/
function Case(name, post, out) {
function Case(name, post, out, statusCode) {
this.name = name
this.post = post
this.out = out
this.statusCode = statusCode
this.finds = []

@@ -24,3 +26,3 @@ }

Case.prototype.execute = function (url, context, db, done) {
var post = execute(this.post, context),
var post = execute(this.post, context, '<post>'),
that = this

@@ -38,4 +40,4 @@ context.post = post

res.statusCode.should.be.equal(200)
check(out, execute(that.out, context))
res.statusCode.should.be.equal(that.statusCode)
check(out, execute(that.out, context, '<out>'))
async.each(that.finds, function (find, done) {

@@ -42,0 +44,0 @@ find.execute(context, db, done)

// This module uses 'with', so it can't be strict
function __exec(value, context) {
/**
* Eval the given value in the given context
* @param {(Object|string)} value
* @param {Object} context
* @param {string} path A string like '<' + description + '>' to be part of a thrown execption
* @returns {*}
* @throws
*/
module.exports = function (value, context, path) {
'use strict'
var key, r
path = path || ''
if (typeof value === 'string') {
return __eval(value, context)
return __eval(value, context, path)
} else {
r = Object.create(null)
for (key in value) {
r[key] = __exec(value[key], context)
r[key] = module.exports(value[key], context, path + '.' + key)
}

@@ -17,8 +26,11 @@ return r

function __eval(__str, __context) {
with(__context) {
return eval(__str)
function __eval(__str, __context, __path) {
try {
with(__context) {
return eval(__str)
}
} catch (e) {
e.message += ' in ' + __path
throw e
}
}
module.exports = __exec
}

@@ -16,3 +16,3 @@ 'use strict'

Find.prototype.execute = function (context, db, done) {
var selector = execute(this.value, context),
var selector = execute(this.value, context, '<find in ' + this.collection + '>'),
that = this

@@ -19,0 +19,0 @@ db.collection(this.collection).findOne(selector, function (err, doc) {

@@ -48,3 +48,3 @@ 'use strict'

// Prepare the document
context[that.name] = execute(this.value, context)
context[that.name] = execute(this.value, context, '<' + this.name + ' in ' + this.collection + '>')
db.collection(this.collection).insert(context[that.name], {

@@ -51,0 +51,0 @@ w: 1

{
"name": "api-test",
"version": "0.1.0",
"version": "0.2.0",
"author": "Sitegui <sitegui@sitegui.com.br>",

@@ -5,0 +5,0 @@ "description": "API testing made simple",

@@ -14,2 +14,3 @@ /**

* * x|y means either x or y
* * [D] means a digit
*

@@ -20,3 +21,3 @@ * {file} = <header> / {fixup}? / {test}+

* {fixup} = '## DB' / ({insertion} | {clear})*
* {test} = '## ' _caseName_ / '### Post' / {obj} / '### Out' / {obj} / {find}*
* {test} = '## ' _caseName_ / ('### Post' / {obj})? / {out}? / {find}*
*

@@ -26,2 +27,3 @@ * {insertion} = '### ' _docName_ ' in ' _collection_ / {obj}

* {obj} = '\t' (_value_ | {subobj} | <prop>)
* {out} = '### Out' (' ' <statusCode>)? / {obj}
* {find} = '### Find in ' _collection_ / {obj}

@@ -31,2 +33,3 @@ *

* <prop> = _key_ ':' _value_
* <statusCode> = [D] [D] [D]
*

@@ -138,18 +141,39 @@ * Paragraph text is ignored (it can be used for documentation)

function parseCase(test, lines, i, originalLines) {
var name, post, out, statusCode
// Test case name
if (!checkHeader(lines[i], 2)) {
throwSyntaxError('Expected "## _caseName_"', lines[i], originalLines)
} else if (!checkHeader(lines[i + 1], 3, 'Post')) {
throwSyntaxError('Expected "### Post"', lines[i + 1], originalLines)
} else if (!(lines[i + 2] instanceof Obj)) {
throwSyntaxError('Expected an {obj}', lines[i + 2], originalLines)
} else if (!checkHeader(lines[i + 3], 3, 'Out')) {
throwSyntaxError('Expected "### Out"', lines[i + 3], originalLines)
} else if (!(lines[i + 4] instanceof Obj)) {
throwSyntaxError('Expected an {obj}', lines[i + 4], originalLines)
}
name = lines[i].value
i++
var testCase = new Case(lines[i].value, lines[i + 2].value, lines[i + 4].value)
// Post
if (checkHeader(lines[i], 3, 'Post')) {
if (!(lines[i + 1] instanceof Obj)) {
throwSyntaxError('Expected an {obj}', lines[i + 1], originalLines)
}
post = lines[i + 1].value
i += 2
} else {
post = {}
}
// Out
if (checkHeader(lines[i], 3) && lines[i].value.match(/^Out( \d{3})?$/)) {
if (!(lines[i + 1] instanceof Obj)) {
throwSyntaxError('Expected an {obj}', lines[i + 1], originalLines)
}
out = lines[i + 1].value
statusCode = lines[i].value === 'Out' ? 200 : Number(lines[i].value.substr(4))
i += 2
} else {
out = {}
statusCode = 200
}
var testCase = new Case(name, post, out, statusCode)
test.cases.push(testCase)
i += 5
// Finds
while (i < lines.length && !checkHeader(lines[i], 2)) {

@@ -198,2 +222,3 @@ if (!checkHeader(lines[i], 3) || lines[i].value.indexOf('Find in ') !== 0) {

* @param {number} [context=3]
* @returns {string}
*/

@@ -215,2 +240,3 @@ function getSourceContext(originalLines, start, end, context) {

* @param {string[]} originalLines
* @throws
*/

@@ -217,0 +243,0 @@ function throwSyntaxError(msg, token, originalLines) {

@@ -6,3 +6,3 @@ # API Test

## Install
`npm install api-test --save`
`npm install api-test --save-dev`

@@ -20,3 +20,3 @@ ## Usage

randomId()
### Out
### Out 400
error:

@@ -78,6 +78,6 @@ code: 200

### Test cases
A test case has three sections:
A test case has three optional sections:
* `Post`: the JSON body to send by POST. Must start with a header like `### Post`
* `Out`: the expected JSON output. Must start with a header like `### Out`
* `Post`: the JSON body to send by POST. Must start with a header like `### Post`. Default: empty JSON object `{}`
* `Out`: the expected JSON output. Must start with a header like `### Out [_statusCode_]`. Default: no output checking. The _statusCode_ is optional and default to 200
* `Finds`: optional DB assertions. Must start with a header like `### Find in _collection_`

@@ -108,3 +108,6 @@

* `randomId()`: return a random mongo-id as a 24-hex-char string
* `randomStr(len)`: return a random string with length `len`
* `randomStr([len=7], [alphabet=a-zA-Z0-9+/])`
* `randomHex([len=7])`
* `randomCode([len=7])`
* `randomEmail([domain='example.com'])`
* `empty`: the empty object `{}`

@@ -121,4 +124,38 @@ * `post`: the request body of the current test case

* `describe`, `it`, `before`: (optional) the mocha interface. Defaults to global mocha functions
* `context`: (optional) define your own variables/functions accessible from object definitions, to help writing tests.
* `context`: (optional) define your own variables/functions accessible to object definitions
## Custom context
You can use custom context to help writing tests. All default context variables and methods will still be accessible (unless overwritten).
For example: if all endpoints return errors like this: `{error: {code: _code_, message: _aDebugString_}}`, you can pass as context:
```
options.context = {
error: function (code) {
return {
error: {
code: code,
message: String
}
}
}
}
```
And then write a test case like this:
```
## Invalid email should give error 200
### Post
user:
email: randomEmail()
### Out
error(200)
```
Instead of repeating youself with:
```
error:
code: 200
message: String
```
## Examples

@@ -130,4 +167,4 @@ See more test examples in the folder 'test/api-test'

## Road map
## TODO
* Array notation: there is no way to declare an array yet
* Better failure message
* Make request to arbitrary endpoints in a test case
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc