lambda-tester
Advanced tools
@@ -0,1 +1,13 @@ | ||
## 2.0.0 (2016-04-09) | ||
New: | ||
* Can now use Promises within verifiers | ||
* Supports Lambda Callbacks | ||
Improved: | ||
* No longer requires the 'done' callback from mocha. Expect handlers now return promises that can be resolved/rejected by mocha. | ||
Compatibility: | ||
* Node.js 4.3.2 or higher | ||
## 1.0.1 (2016-04-03) | ||
@@ -2,0 +14,0 @@ |
285
lib/index.js
@@ -9,40 +9,50 @@ 'use strict'; | ||
if( err ) { | ||
if( err ) { | ||
return this.fail( err ); | ||
return this.fail( err ); | ||
} | ||
return this.succeed( result ); | ||
} | ||
return this.succeed( result ); | ||
} | ||
}; | ||
} | ||
function createSucceedContext( tester, done ) { | ||
function createFailCallback( reject ) { | ||
var context = createContext( tester ); | ||
return function( err, result ) { | ||
context.succeed = function( result ) { | ||
if( err ) { | ||
if( tester.resultVerifier ) { | ||
let failError = new Error( 'callback called with error parameter' ); | ||
failError.cause = err; | ||
try { | ||
tester.resultVerifier( result ); | ||
return reject( failError ); | ||
} | ||
catch( err ) { | ||
return done( err ); | ||
} | ||
} | ||
let failError = new Error( 'callback called' ); | ||
failError.result = result; | ||
done(); | ||
}; | ||
reject( failError ); | ||
}; | ||
} | ||
function createCallbackContext( tester, reject ) { | ||
let context = createContext( tester ); | ||
context.succeed = function( result ) { | ||
var failError = new Error( 'context.succeed() called before callback' ); | ||
failError.result = result; | ||
reject( failError ); | ||
}; | ||
context.fail = function( err ) { | ||
var failError = new Error( 'encountered error but expected the handler to succeed' ); | ||
failError.cause = err; | ||
var failError = new Error( 'context.fail() called before callback' ); | ||
failError.cause = err; | ||
done( failError ); | ||
}; | ||
reject( failError ); | ||
}; | ||
@@ -52,116 +62,225 @@ return context; | ||
function createFailContext( tester, done ) { | ||
function addLegecyVerify( promise ) { | ||
var context = createContext( tester ); | ||
promise.verify = function( done ) { | ||
context.succeed = function( result ) { | ||
return promise.then( | ||
function() { | ||
var failError = new Error( 'encountered successful operation but expected failure' ); | ||
failError.result = result; | ||
done(); | ||
}, | ||
function( err ) { | ||
done( failError ); | ||
}; | ||
done( err ); | ||
} | ||
); | ||
} | ||
} | ||
context.fail = function( err ) { | ||
function verifyResult( result, verifier, resolve, reject ) { | ||
if( tester.resultVerifier ) { | ||
try { | ||
resolve( verifier( result ) ); | ||
} | ||
catch( err ) { | ||
reject( err ); | ||
} | ||
} | ||
class LambdaTester { | ||
constructor( handler ) { | ||
this._handler = handler; | ||
this._event = {}; | ||
} | ||
event( evt ) { | ||
if( !evt ) { | ||
throw new Error( 'missing event' ); | ||
} | ||
this._event = evt; | ||
return this; | ||
} | ||
expectSucceed( resultVerifier ) { | ||
if( !resultVerifier ) { | ||
resultVerifier = function() {}; | ||
} | ||
var context = createContext( this ); | ||
var self = this; | ||
let succeedPromise = new Promise( function( resolve, reject ) { | ||
context.succeed = function( result ) { | ||
verifyResult( result, resultVerifier, resolve, reject ); | ||
}; | ||
context.fail = function( err ) { | ||
var failError = new Error( 'encountered error but expected the handler to succeed' ); | ||
failError.cause = err; | ||
reject( failError ); | ||
}; | ||
let callback = createFailCallback( reject ); | ||
try { | ||
tester.resultVerifier( err ); | ||
self._handler( self._event, context, callback ); | ||
} | ||
catch( verifyErr ) { | ||
catch( err ) { | ||
return done( verifyErr ); | ||
reject( err ); | ||
} | ||
} | ||
}); | ||
done(); | ||
// support for v1 users | ||
addLegecyVerify( succeedPromise ); | ||
return succeedPromise; | ||
} | ||
return context; | ||
} | ||
expectFail( resultVerifier ) { | ||
function LambdaTester( handler ) { | ||
if( !resultVerifier ) { | ||
if( !handler ) { | ||
resultVerifier = function() {}; | ||
} | ||
throw new Error( 'missing handler' ); | ||
} | ||
var context = createContext( this ); | ||
if( this === undefined ) { | ||
var self = this; | ||
return new LambdaTester( handler ); | ||
} | ||
let failPromise = new Promise( function( resolve, reject ) { | ||
this._handler = handler; | ||
context.fail = function( errResult ) { | ||
this._event = {}; | ||
verifyResult( errResult, resultVerifier, resolve, reject ); | ||
}; | ||
} | ||
context.succeed = function( result ) { | ||
LambdaTester.prototype.event = function( event ) { | ||
var failError = new Error( 'encountered successful operation but expected failure' ); | ||
failError.result = result; | ||
if( !event ) { | ||
reject( failError ); | ||
}; | ||
throw new Error( 'missing event' ); | ||
let callback = createFailCallback( reject ); | ||
try { | ||
self._handler( self._event, context, callback ); | ||
} | ||
catch( err ) { | ||
reject( err ); | ||
} | ||
}); | ||
// support for v1 users | ||
addLegecyVerify( failPromise ); | ||
return failPromise; | ||
} | ||
this._event = event; | ||
expectError( resultVerifier ) { | ||
return this; | ||
} | ||
if( !resultVerifier ) { | ||
resultVerifier = function() {}; | ||
} | ||
LambdaTester.prototype.expectSucceed = function( resultVerifier ) { | ||
var self = this; | ||
this.resultVerifier = resultVerifier; | ||
return new Promise( function( resolve, reject ) { | ||
this.verifyOperation = "succeed"; | ||
var context = createCallbackContext( self, reject ); | ||
return this; | ||
} | ||
var callback = function( err, result ) { | ||
LambdaTester.prototype.expectFail = function( resultVerifier ) { | ||
if( err ) { | ||
this.resultVerifier = resultVerifier; | ||
return verifyResult( err, resultVerifier, resolve, reject ); | ||
} | ||
this.verifyOperation = "fail"; | ||
var failError = new Error( 'expecting error' ); | ||
failError.result = result; | ||
return this; | ||
} | ||
reject( failError ); | ||
} | ||
LambdaTester.prototype.verify = function( done ) { | ||
try { | ||
if( !done ) { | ||
self._handler( self._event, context, callback ); | ||
} | ||
catch( err ) { | ||
throw new Error( 'missing callback' ); | ||
reject( err ); | ||
} | ||
}); | ||
} | ||
if( !this.verifyOperation ) { | ||
expectResult( resultVerifier ) { | ||
throw new Error( 'call expectSucceed() or expectFailure() before calling verify' ); | ||
} | ||
if( !resultVerifier ) { | ||
var context; | ||
resultVerifier = function() {}; | ||
} | ||
switch( this.verifyOperation ) { | ||
var self = this; | ||
case 'succeed': | ||
context = createSucceedContext( this, done ); | ||
break; | ||
return new Promise( function( resolve, reject ) { | ||
case 'fail': | ||
context = createFailContext( this, done ); | ||
break; | ||
var context = createCallbackContext( self, reject ); | ||
default: | ||
throw new Error( 'unknown operation: ' + this.verifyOperation ); | ||
var callback = function( err, result ) { | ||
if( err ) { | ||
var failError = new Error( 'expecting result' ); | ||
failError.cause = err; | ||
return reject( failError ); | ||
} | ||
return verifyResult( result, resultVerifier, resolve, reject ); | ||
} | ||
try { | ||
self._handler( self._event, context, callback ); | ||
} | ||
catch( err ) { | ||
reject( err ); | ||
} | ||
}); | ||
} | ||
return this._handler( this._event, context ); | ||
} | ||
function create( handler ) { | ||
module.exports = LambdaTester; | ||
if( !handler ) { | ||
throw new Error( 'missing handler' ); | ||
} | ||
return new LambdaTester( handler ); | ||
} | ||
module.exports = create; |
{ | ||
"name": "lambda-tester", | ||
"version": "1.0.1", | ||
"version": "2.0.0", | ||
"description": "Helps unit test AWS Lambda handlers", | ||
@@ -13,2 +13,5 @@ "main": "index.js", | ||
], | ||
"engines": { | ||
"node": ">=4.3.2" | ||
}, | ||
"repository": { | ||
@@ -27,4 +30,5 @@ "type": "git", | ||
"istanbul": "^0.4.2", | ||
"mocha": "^2.4.5" | ||
"mocha": "^2.4.5", | ||
"sinon": "^1.17.3" | ||
} | ||
} |
116
README.md
@@ -10,12 +10,17 @@ [](https://travis-ci.org/vandium-io/lambda-tester) | ||
* Works asynchronously like Lambda does | ||
* Supports Promises | ||
* Easily integrates with test frameworks | ||
* No external dependencies | ||
* Lightweight and won't impact performance | ||
* Works with Node 0.10.36 | ||
* Works with Node 4.3.2+ | ||
## Installation | ||
## Installation | ||
Install via npm. | ||
npm install lambda-tester --save-dev | ||
## Compatibility | ||
Version 2.0 targets Lambda handlers using Node 4.3.2. If you require support for Node 0.10.36 then use version 1.0.x. | ||
## Getting Started | ||
@@ -32,8 +37,7 @@ | ||
it( 'test success', function( done /*important!*/ ) { | ||
LambdaTester( myHandler ) | ||
it( 'test success', function() { | ||
return LambdaTester( myHandler ) | ||
.event( { name: 'Fred' } ) | ||
.expectSucceed() | ||
.verify( done ); | ||
.expectSucceed(); | ||
}); | ||
@@ -54,8 +58,7 @@ }); | ||
it( 'test failure', function( done /*important!*/ ) { | ||
LambdaTester( myHandler ) | ||
it( 'test failure', function() { | ||
return LambdaTester( myHandler ) | ||
.event( { name: 'Unknown' } ) | ||
.expectFail() | ||
.verify( done ); | ||
.expectFail(); | ||
}); | ||
@@ -67,3 +70,3 @@ }); | ||
Please note that a `done` callback is *required* since use an asynchronous mechanism to report success or failure. | ||
Please note that you must return the `LambdaTester` back to the framework since `lambda-tester` is asynchronous and uses Promises. | ||
@@ -85,12 +88,11 @@ ## Verifying Success | ||
it( 'test success', function( done /*important!*/ ) { | ||
LambdaTester( myHandler ) | ||
it( 'test success', function() { | ||
return LambdaTester( myHandler ) | ||
.event( { name: 'Fred' } ) | ||
.expectSucceed( function( result ) { | ||
expect( result.userId ).to.exist; | ||
expect( result.user ).to.equal( 'fredsmith' ); | ||
}) | ||
.verify( done ); | ||
}); | ||
}); | ||
@@ -114,11 +116,10 @@ }); | ||
it( 'test success', function( done /*important!*/ ) { | ||
LambdaTester( myHandler ) | ||
it( 'test failure', function() { | ||
return LambdaTester( myHandler ) | ||
.event( { name: 'Unknown' } ) | ||
.expectFail( function( err ) { | ||
expect( err.message ).to.equal( 'User not found' ); | ||
}) | ||
.verify( done ); | ||
}); | ||
}); | ||
@@ -128,2 +129,65 @@ }); | ||
## Verifying Lambda Callbacks | ||
On April 8, 2016 AWS Lambda introduced support for Lambda callbacks that replace the need to call `context.fail()` or `context.succeed()`. | ||
Lambda handlers with support for callbacks use the typical Node.js asynchronous signature: | ||
```js | ||
exports.handler = function( event, context, callback ) { | ||
callback( null, 'success!' ); | ||
} | ||
``` | ||
To verify that `callback( null, result )` was called: | ||
```js | ||
var LambdaTester = require( 'lambda-tester' ); | ||
// your favorite validation tool here | ||
var expect = require( 'chai' ).expect; | ||
var myHandler = require( '../index' ).handler; | ||
describe( 'handler', function() { | ||
it( 'test callback( null, result )', function() { | ||
return LambdaTester( myHandler ) | ||
.event( { name: 'Fred' } ) | ||
.expectResult( function( result ) { | ||
expect( result.userId ).to.exist; | ||
expect( result.user ).to.equal( 'fredsmith' ); | ||
}); | ||
}); | ||
}); | ||
``` | ||
To verify that `callback( err )` was called: | ||
```js | ||
var LambdaTester = require( 'lambda-tester' ); | ||
// your favorite validation tool here | ||
var expect = require( 'chai' ).expect; | ||
var myHandler = require( '../index' ).handler; | ||
describe( 'handler', function() { | ||
it( 'test callback( err )', function() { | ||
return LambdaTester( myHandler ) | ||
.event( { name: 'Unknown' } ) | ||
.expectError( function( err ) { | ||
expect( err.message ).to.equal( 'User not found' ); | ||
}); | ||
}); | ||
}); | ||
``` | ||
## Feedback | ||
@@ -130,0 +194,0 @@ |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
15120
47.2%10
11.11%179
77.23%218
41.56%0
-100%4
33.33%