stub-azure-function-context
Version:
Provides an object similar to Function Runtime's context for use in unit testing
161 lines • 5.58 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createContextForFunction = createContextForFunction;
const crypto_1 = require("crypto");
const utils_1 = require("./utils");
function createConsoleLogger() {
const logger = (...args) => console.log(...args);
logger.verbose = (...args) => console.debug(...args);
logger.info = (...args) => console.info(...args);
logger.warn = (...args) => console.warn(...args);
logger.error = (...args) => console.error(...args);
return logger;
}
function createBaseContext(azFunction, bindingDefinitions) {
const invocationId = (0, crypto_1.randomUUID)();
return {
invocationId: invocationId,
executionContext: {
invocationId,
functionName: azFunction.name,
functionDirectory: __dirname,
retryContext: null,
},
bindings: {},
bindingData: {
invocationId,
},
traceContext: {
traceparent: `00-${(0, crypto_1.randomBytes)(16).toString('hex')}-${(0, crypto_1.randomBytes)(8).toString('hex')}-00`,
tracestate: null,
attributes: null,
},
bindingDefinitions,
log: createConsoleLogger(),
};
}
function createContextForFunction(azFunction, bindingDefinitions, bindingData, resolver) {
const context = createBaseContext(azFunction, typeof bindingDefinitions === 'string' ? require(bindingDefinitions).bindings : bindingDefinitions);
const { trigger, inputs, outputs } = (0, utils_1.extractBindings)(context.bindingDefinitions);
if (trigger) {
const binding = bindingData[trigger.name].toContextBinding();
Object.assign(context.bindings, {
[trigger.name]: binding,
});
Object.assign(context.bindingData, {
...bindingData[trigger.name].toBindingData(),
});
if (trigger.type.toLowerCase() === 'httptrigger') {
context.req = binding;
}
}
inputs.forEach((input) => {
const binding = bindingData[input.name].toContextBinding();
Object.assign(context.bindings, {
[input.name]: binding,
});
Object.assign(context.bindingData, {
...bindingData[trigger.name].toBindingData(),
});
});
const httpOutput = outputs.find(({ type }) => type.toLowerCase() === 'http');
let doneCalled = false;
if (httpOutput) {
Object.assign(context, {
res: {
statusCode: 200,
headers: {},
cookies: [],
status(statusCode) {
this.statusCode = statusCode;
return this;
},
setHeader(header, val) {
this.headers = Object.assign(this.headers ?? {}, {
[header.toLowerCase()]: val,
});
return this;
},
getHeader(header) {
if (this.headers) {
return this.headers[header.toLowerCase()];
}
},
set(field, val) {
return this.setHeader(field, val);
},
get(field) {
return this.getHeader(field);
},
removeHeader(field) {
if (this.headers) {
delete this.headers[field.toLowerCase()];
}
return this;
},
type(type) {
this.setHeader('content-type', type);
return this;
},
send(body) {
this.body = body;
context.done();
return this;
},
sendStatus(statusCode) {
this.statusCode = statusCode;
context.done();
return this;
},
header(field, val) {
return this.setHeader(field, val);
},
json(body) {
this.type('application/json');
this.send(body);
},
end(body) {
return this.send(body);
},
},
});
}
const done = function (err, result) {
if (doneCalled) {
return;
}
doneCalled = true;
if (err) {
resolver(err);
}
else if (outputs.some(({ name }) => name === '$return')) {
if (httpOutput?.name === '$return') {
Object.assign(context, { res: result });
}
resolver(null, result);
}
else {
if (result) {
Object.assign(context.bindings, result);
}
else if (httpOutput) {
if (context.bindings[httpOutput.name]) {
Object.assign(context, {
res: context.bindings[httpOutput.name],
});
}
else {
Object.assign(context.bindings, {
[httpOutput.name]: context.res,
});
}
}
resolver(null, context);
}
};
Object.assign(context, {
done: done.bind(context),
});
return context;
}
//# sourceMappingURL=context-builder.js.map