stub-azure-function-context
Advanced tools
Comparing version
{ | ||
"name": "stub-azure-function-context", | ||
"version": "1.4.0", | ||
"version": "2.0.0-alpha.1", | ||
"description": "Provides an object similar to Function Runtime's context for use in unit testing", | ||
"main": "stub-azure-function-context.js", | ||
"main": "index.js", | ||
"directories": { | ||
@@ -10,5 +10,4 @@ "test": "test" | ||
"files": [ | ||
"stub-azure-function-context.js", | ||
"README.md", | ||
"LICENSE" | ||
"lib/", | ||
"stub-azure-function-context.js" | ||
], | ||
@@ -48,4 +47,5 @@ "scripts": { | ||
"dependencies": { | ||
"moment": "^2.24.0", | ||
"uuid": "^3.3.2" | ||
} | ||
} |
166
README.md
@@ -5,27 +5,34 @@ # stub-azure-function-context | ||
Aims to implement the context object as described on the [Azure Functions JavaScript Developer Guide](https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node#context-object). | ||
Aims to implement the context object as described on the [Azure Functions JavaScript Developer Guide](https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node#context-object) | ||
and allow developers to call azure functions for testing purposes. | ||
### Usage | ||
## Usage | ||
By default the behaviour assumes a `req` HTTP trigger and a `res` HTTP output, but if you have more exotic config, then | ||
you can set that up! | ||
This library works by accepting a set of binding definitions much like you would place in the `function.json` file. | ||
If you follow the "ordered argument" pattern then you'll need to define the triggers/outputs in the same order | ||
as in your `function.json`. | ||
The is support for the different [input styles](https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node#inputs) | ||
which allow for: | ||
From 1.0.3 this library supports endpoint handlers returning Promise objects, and by extension, the async/await style. | ||
1. Ordered arguments to your function, eg: `function (context, myTrigger, myInput, myOtherInput, ...)` | ||
2. Named bindings to the context object: eg: `context.bindings.myTrigger`, `context.bindings.myInput`, etc | ||
`stubContext` resolves with an object containing: | ||
And the different [output styles](https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node#outputs) | ||
which allow for: | ||
``` | ||
{ | ||
context: context, // the actual stubbed context object after your function manipulates it | ||
err: null|Error, // any error thrown or passed to context.done; eg: context.done(new Error("Oops")) | ||
propertyBag: {}, // object of any overrides you want to make on your outputs | ||
} | ||
``` | ||
1. A function which is a Promise and resolves to an object with keys that match output bindings, eg: | ||
`return { myOutput: 'message', myOtherOutout: { body: 'success' } }` | ||
2. Returning a value for a specified binding, eg: by using `name: '$return'` in the binding definition | ||
3. Assigning values to `context.bindings`, eg: `context.bindings.myOutput = 'message'`, etc | ||
4. Special support for HTTP Responses, eg: (`context.res.send(body?)`) | ||
When the function has resolved the library will return either the manipulated context object to make assertions | ||
against or the returned value *if* the special `$return` name is used for one of the output bindings. | ||
If you follow the "ordered argument" pattern then you'll need to define the triggers/outputs in the same order | ||
as in your `function.json`. | ||
By default, logging uses `console` as a backend, although you can import and use `setContextLogger` to set your own. | ||
Your logger will need to conform to the same interface as `console` and will be wrapped to work with the `context.log` interface. | ||
Only the methods defined in the developer guide are available in the `stubContext` call: | ||
Only the logger methods defined in the developer guide are available in the `stubContext` call: | ||
@@ -37,8 +44,65 @@ * `error` | ||
## Supported triggers and bindings | ||
### Usage examples: | ||
At the moment the following binding types are supported: | ||
- blob | ||
- http | ||
- queue | ||
- table | ||
- timer | ||
Complete list of bindings: https://docs.microsoft.com/bs-latn-ba/azure/azure-functions/functions-triggers-bindings#supported-bindings | ||
## Function runner | ||
The `runStubFunctionFromBindings` function is designed to take a function that conforms to the azure function spec, an array of bindings | ||
which are defined in a similar way to those in `function.json`, and an optional `now` value (for mocking the time). | ||
The function then builds a mocked `context` object and calls the function as it would be by the azure function runtime. | ||
`runStubFunctionFromBindings` will return a `Promise` that will resolve once the function being tested calls `context.done` | ||
or, if it's a Promise itself, when it resolves. The `runStubFunctionFromBindings` will resolve as either the `context` object | ||
with the output bindings assigned (allowing assertions to be made against it) OR as the value that the Promise resolved to *if* | ||
the binding name `$return` was used. | ||
If the function errors, an error will be thrown. | ||
It is possible to build your own custom context object and run that against the function using `callFunction` and is intended for | ||
advanced uses where the `runStubFunctionFromBindings` does not meet requirements (such as returning both a `$return` and context | ||
object is required - though this is not recommended by azure). | ||
### Binding definitions | ||
The binding definitions accepted by the function runner are designed to accept the same syntax as the `function.json` file with a | ||
few differences. The most crucial is that triggers (eg: `httpTrigger`, `timerTrigger`) need a trigger object so that we can bind | ||
a mocked trigger to the context object. This should be placed in the property `data` eg: | ||
```js | ||
runStubFunctionFromBindings(functionToTest, [ | ||
{ name: 'req', type: 'httpTrigger', direction: 'in', data: createHttpTrigger() }, | ||
]); | ||
``` | ||
const { stubContext, setContextLogger } = require('stub-azure-function-context'); | ||
A set of helper methods have been exposed to make creating the triggers more simple: | ||
- `createHttpTrigger` | ||
- `createBlobTrigger` | ||
- `createQueueTrigger` | ||
- `createQueueTriggerFromMessage` | ||
- `createTableTrigger` | ||
- `createTimerTrigger` | ||
These all take a set of arguments to quickly create a trigger object that will conform to the expected trigger shapes. | ||
However, if these don't meet your needs, you can supply your own object or augment the returned object. | ||
It is worth noting that the `queue` trigger shape does not conform to the queue messages shape received from actual azure queues. | ||
Therefore another helper method has been provided: `createQueueTriggerFromMessage` which takes 1 argument (the queue message) and | ||
maps it to the expected shape for the trigger. This allows better integration with a mocked environment when using something | ||
like [azurite](https://hub.docker.com/_/microsoft-azure-storage-azurite). | ||
### HTTP examples: | ||
```js | ||
const { runStubFunctionFromBindings, createHttpTrigger } = require('stub-azure-function-context'); | ||
const functionToTest = require('../function-under-test'); | ||
@@ -52,8 +116,14 @@ | ||
it('returns 200', async () => { | ||
const { context, err, propertyBag, } = await stubContext(functionToTest); | ||
const context = await runStubFunctionFromBindings(functionToTest, [ | ||
{ type: 'httpTrigger', name: 'req', direction: 'in', data: createHttpTrigger('GET', 'http://example.com') }, | ||
{ type: 'http', name: 'res', direction: 'out' }, | ||
], new Date()); | ||
expect(context).to.have.nested.property('res.status', 200); | ||
}); | ||
it('returns 200 in promise/a+ style', (done) => { | ||
stubContext(functionToTest) | ||
.then(({ context, err, propertyBag }) => { | ||
runStubFunctionFromBindings(functionToTest, [ | ||
{ type: 'httpTrigger', name: 'req', direction: 'in', data: createHttpTrigger('GET', 'http://example.com') }, | ||
{ type: 'http', name: 'res', direction: 'out' }, | ||
], new Date()) | ||
.then((context) => { | ||
expect(context).to.have.nested.property('res.status', 200); | ||
@@ -64,10 +134,50 @@ done(); | ||
}); | ||
it('change trigger values before calling your function under test', async () => { | ||
const { context } = await stubContext((context, req, ...otherTriggers) => { | ||
req.body = { 'helpful': 'test object' }; | ||
return functionToTest(context, req, ...otherTriggers); | ||
}); | ||
expect(context).to.have.nested.property('res.body.helpful', 'test object'); | ||
}); | ||
it('supports $return values', async () => { | ||
const response = await runStubFunctionFromBindings(functionToTest, [ | ||
{ type: 'httpTrigger', name: 'req', direction: 'in', data: createHttpTrigger('GET', 'http://example.com') }, | ||
{ type: 'http', name: '$return', direction: 'out' }, | ||
], new Date()); | ||
expect(response).to.have.nested.property('status', 200); | ||
}); | ||
}); | ||
``` | ||
### Queue examples | ||
```js | ||
const { | ||
runStubFunctionFromBindings, | ||
createQueueTrigger, | ||
createQueueTriggerFromMessage, | ||
} = require('stub-azure-function-context'); | ||
const functionToTest = require('./function-to-tes'); | ||
const { promisify } = require('util'); | ||
const { createQueueService, QueueMessageEncoder } = require('azure-storage'); | ||
describe('queue triggered message', () => { | ||
let queue; | ||
before('set up queue', () => { | ||
const queueSvc = createQueueService(); | ||
queueSvc.messageEncoder = new QueueMessageEncoder.TextBase64QueueMessageEncoder(); | ||
queue = { | ||
get: promisify(queueSvc.getMessage.bind(queueSvc)), | ||
create: promisify(queueSvc.createMessage.bind(queueSvc)), | ||
}; | ||
return queue.create('my-message'); | ||
}); | ||
it('accepts a message', async () => { | ||
const message = await queue.get(); | ||
const context = await runStubFunctionFromBindings(functionToTest, [ | ||
{ name: 'myInput', direction: 'in', type: 'queueTrigger', data: createQueueTriggerFromMessage(message) } | ||
]); | ||
expect(context.bindings.myInput).to.have.property('queueTrigger', 'my-message'); | ||
}); | ||
it('accepts a mocked message', async () => { | ||
const messageText = 'my-other-message'; | ||
const context = await runStubFunctionFromBindings(functionToTest, [ | ||
{ name: 'myInput', direction: 'in', type: 'queueTrigger', data: createQueueTrigger(messageText) } | ||
]); | ||
expect(context.bindings.myInput).to.have.property('queueTrigger', 'my-other-message'); | ||
}); | ||
}); | ||
``` |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
26587
125.1%12
200%501
178.33%180
157.14%2
100%1
Infinity%1
Infinity%+ Added
+ Added