ebdd
Version:
Extended BDD interface for Mocha
601 lines (592 loc) • 25.6 kB
JavaScript
// ebdd – undefined
(function () {
'use strict';
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
function __spreadArray(to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
}
function bindArguments(fn, args) {
var boundFn = function () {
var returnValue = fn.apply(this, args);
return returnValue;
};
return boundFn;
}
function bindArgumentsButLast(fn, args) {
var boundFn = function (lastArg) {
var argsAndLast = __spreadArray(__spreadArray([], args, true), [lastArg], false);
var returnValue = fn.apply(this, argsAndLast);
return returnValue;
};
return boundFn;
}
var ExtensibleArray = function () { };
ExtensibleArray.prototype = Array.prototype;
var TitleFormatter = (function () {
function TitleFormatter(titlePattern, paramCount) {
function titleFormatter(params) {
function formatChunk(chunk) {
if (typeof chunk === 'string')
return chunk;
var value = params[chunk.paramIndex];
for (var _i = 0, chunk_1 = chunk; _i < chunk_1.length; _i++) {
var propName = chunk_1[_i];
if (value === undefined || value === null)
return undefined;
value = value[propName];
}
return value;
}
var title = chunks.map(formatChunk).join('');
return title;
}
var chunks = createChunks(titlePattern, paramCount);
return titleFormatter;
}
return TitleFormatter;
}());
function createChunks(titlePattern, paramCount) {
function findNextPlaceholder() {
var _a, _b, _c;
var rankMatch;
var start;
for (;;) {
rankMatch = rankRegExp.exec(titlePattern);
if (!rankMatch)
return null;
start = rankMatch.index;
var prevChar = titlePattern[start - 1];
if (prevChar !== '\\')
break;
rankRegExp.lastIndex = start + 1;
}
var rank = rankMatch[1];
var paramIndex = rank ? rank - 1 : 0;
var placeholder = [];
var index = rankRegExp.lastIndex;
var propNameMatch;
while (propNameMatch = propNameRegExp.exec(titlePattern.slice(index))) {
var propName = (_b = (_a = propNameMatch[1]) !== null && _a !== void 0 ? _a : propNameMatch[2]) !== null && _b !== void 0 ? _b : ((_c = propNameMatch[3]) !== null && _c !== void 0 ? _c : propNameMatch[4]).replace(/\\([^])/g, '$1');
placeholder.push(propName);
index += propNameMatch[0].length;
}
rankRegExp.lastIndex = index;
makePlaceholder(placeholder, start, index, paramIndex);
validatePlaceholder(placeholder, !rank);
return placeholder;
}
function getRawPlaceholder(_a) {
var start = _a.start, end = _a.end;
var rawPlaceholder = titlePattern.substring(start, end);
return rawPlaceholder;
}
function pushStaticChunk(start) {
if (end < start) {
var chunk = titlePattern.substring(end, start).replace(/\\#/g, '#');
chunks.push(chunk);
}
}
function validatePlaceholder(placeholder, rankless) {
if (rankless) {
if (paramCount > 1) {
var rawPlaceholder = getRawPlaceholder(placeholder);
var rankSpecification = void 0;
switch (paramCount) {
case 2:
rankSpecification = '#1 or #2';
break;
case 3:
rankSpecification = '#1, #2 or #3';
break;
default:
rankSpecification = "#1, #2, \u2026 #".concat(paramCount);
break;
}
var message = "The placeholder ".concat(rawPlaceholder, " is ambiguous because there are ").concat(paramCount, " parameters. Use ").concat(rankSpecification, " instead of # to refer to a specific parameter.");
throw Error(message);
}
}
else {
if (placeholder.paramIndex >= paramCount) {
var rawPlaceholder = getRawPlaceholder(placeholder);
var predicate = paramCount === 1 ? 'is only one parameter' : "are only ".concat(paramCount, " parameters");
var message = "The placeholder ".concat(rawPlaceholder, " is invalid because there ").concat(predicate, ".");
throw Error(message);
}
}
}
var rankRegExp = /#([1-9]\d*)?(?![$\w\u0080-\uffff])/g;
var chunks = [];
var end = 0;
{
var placeholder = void 0;
while (placeholder = findNextPlaceholder()) {
var start = placeholder.start;
pushStaticChunk(start);
chunks.push(placeholder);
(end = placeholder.end);
}
}
pushStaticChunk(titlePattern.length);
return chunks;
}
function makePlaceholder(placeholder, start, end, paramIndex) {
placeholder.start = start;
placeholder.end = end;
placeholder.paramIndex = paramIndex;
}
var propNameRegExp = /^\.((?!\d)[$\w\u0080-\uffff]+)|^\[(?:(0|-?[1-9]\d*)|"((?:[^\\"]|\\[^])*)"|'((?:[^\\']|\\[^])*)')]/;
var Brand;
(function (Brand) {
Brand[Brand["NONE"] = 0] = "NONE";
Brand[Brand["XIT"] = 1] = "XIT";
Brand[Brand["XDESCRIBE"] = 2] = "XDESCRIBE";
Brand[Brand["SKIP_OR_ONLY"] = 3] = "SKIP_OR_ONLY";
})(Brand || (Brand = {}));
var Mode;
(function (Mode) {
Mode[Mode["NORMAL"] = 0] = "NORMAL";
Mode[Mode["ONLY"] = 1] = "ONLY";
Mode[Mode["SKIP"] = 2] = "SKIP";
})(Mode || (Mode = {}));
var ParamInfo = (function () {
function ParamInfo(param, mode) {
this.param = param;
this.mode = mode;
if (param instanceof ParamInfo) {
var message = 'Invalid parameter. skip(...), only(...) and when(...) expressions cannot be nested.';
throw TypeError(message);
}
}
return ParamInfo;
}());
var SpecItemArray = (function (_super) {
__extends(SpecItemArray, _super);
function SpecItemArray() {
return _super !== null && _super.apply(this, arguments) || this;
}
SpecItemArray.prototype.timeout = function (ms) {
if (arguments.length) {
for (var _i = 0, _a = this; _i < _a.length; _i++) {
var specItem = _a[_i];
specItem.timeout(ms);
}
return this;
}
{
var sum = 0;
for (var _b = 0, _c = this; _b < _c.length; _b++) {
var specItem = _c[_b];
sum += specItem.timeout();
}
var ms_1 = sum / this.length;
return ms_1;
}
};
return SpecItemArray;
}(ExtensibleArray));
function countParameters(paramCount) {
var paramStr = "".concat(paramCount, " ").concat(paramCount === 1 ? 'parameter' : 'parameters');
return paramStr;
}
function createBDDInterface(context, file, mocha) {
var _this = this;
var _a;
var setMaxListeners = function (maxListeners) {
var _a, _b;
(_b = (_a = _this).setMaxListeners) === null || _b === void 0 ? void 0 : _b.call(_a, maxListeners);
};
var bdd = mocha.constructor.interfaces.bdd;
var maxListeners = this.getMaxListeners !== undefined ?
this.getMaxListeners() : (_a = this._maxListeners) !== null && _a !== void 0 ? _a : 0;
setMaxListeners(0);
bdd(this);
var listeners = this.listeners('pre-require');
var bddPreRequireListener = listeners[listeners.length - 1];
this.removeListener('pre-require', bddPreRequireListener);
setMaxListeners(maxListeners);
bddPreRequireListener.call(this, context, file, mocha);
}
function createEBDDInterface(context, file, mocha) {
function createParameterizedSuiteFunction(baseParamLists, brand) {
function skip(brand) {
var describe = createParameterizedSuiteFunction(skipAll(baseParamLists), brand);
return describe;
}
function stub(titlePattern, fn) {
validateTitlePattern(titlePattern);
var paramCount = baseParamLists[0].length;
validateSuiteCallback(fn, paramCount);
var titleFormatter = new TitleFormatter(titlePattern, paramCount);
var suites = new SpecItemArray();
for (var _i = 0, baseParamLists_1 = baseParamLists; _i < baseParamLists_1.length; _i++) {
var paramList = baseParamLists_1[_i];
var createSuite = getCreateSuite(paramList.mode);
var title = titleFormatter(paramList);
var fnWrapper = bindArguments(fn, paramList);
var suite_1 = createSuite(title, fnWrapper);
suites.parent = suite_1.parent;
suites.push(suite_1);
}
return suites;
}
stub.per =
function (params, paramMapper) {
validateParamMapper(paramMapper);
var paramLists = multiplyParams(params, paramMapper, baseParamLists);
var describe = createParameterizedSuiteFunction(paramLists, brand);
return describe;
};
stub.when =
function (condition) {
return condition ? describe : skip(brand);
};
var describe = makeParameterizableFunction(stub, function () {
return skip(Brand.SKIP_OR_ONLY);
}, function () {
return createParameterizedSuiteFunction(onlyAll(baseParamLists), Brand.SKIP_OR_ONLY);
}, brand);
return describe;
}
function createParameterizedTestFunction(baseParamLists, brand) {
function skip(brand) {
var it = createParameterizedTestFunction(skipAll(baseParamLists), brand);
return it;
}
function stub(titlePattern, fn) {
validateTitlePattern(titlePattern);
var paramCount = baseParamLists[0].length;
validateTestCallback(fn, paramCount);
var titleFormatter = new TitleFormatter(titlePattern, paramCount);
var tests = new SpecItemArray();
for (var _i = 0, baseParamLists_2 = baseParamLists; _i < baseParamLists_2.length; _i++) {
var paramList = baseParamLists_2[_i];
var createTest = getCreateTest(paramList.mode);
var title = titleFormatter(paramList);
var fnWrapper = void 0;
if (fn.length === paramCount) {
fnWrapper = bindArguments(fn, paramList);
}
else {
fnWrapper =
bindArgumentsButLast(fn, paramList);
}
var test_1 = createTest(title, fnWrapper);
tests.parent = test_1.parent;
tests.push(test_1);
}
return tests;
}
stub.per =
function (params, paramMapper) {
validateParamMapper(paramMapper);
var paramLists = multiplyParams(params, paramMapper, baseParamLists);
var it = createParameterizedTestFunction(paramLists, brand);
return it;
};
stub.when =
function (condition) {
return condition ? it : skip(brand);
};
var it = makeParameterizableFunction(stub, function () {
return skip(Brand.SKIP_OR_ONLY);
}, function () {
return createParameterizedTestFunction(onlyAll(baseParamLists), Brand.SKIP_OR_ONLY);
}, brand);
return it;
}
function createUnparameterizedSuiteFunction(baseMode, brand) {
if (baseMode === void 0) { baseMode = Mode.NORMAL; }
if (brand === void 0) { brand = Brand.NONE; }
function stub(title, fn) {
validateTitle(title);
validateSuiteCallback(fn, 0);
var createSuite = getCreateSuite(baseMode);
var suite = createSuite(title, fn);
return suite;
}
stub.per =
function (params, paramMapper) {
validateParamMapper(paramMapper);
var paramLists = createParamLists(params, paramMapper, baseMode);
var describe = createParameterizedSuiteFunction(paramLists, brand);
return describe;
};
stub.when =
function (condition) {
return condition ? describe : createUnparameterizedSuiteFunction(Mode.SKIP, brand);
};
var describe = makeParameterizableFunction(stub, function () {
return createUnparameterizedSuiteFunction(Mode.SKIP, Brand.SKIP_OR_ONLY);
}, function () {
return createUnparameterizedSuiteFunction(maxMode(Mode.ONLY, baseMode), Brand.SKIP_OR_ONLY);
}, brand);
return describe;
}
function createUnparameterizedTestFunction(baseMode, brand) {
if (baseMode === void 0) { baseMode = Mode.NORMAL; }
if (brand === void 0) { brand = Brand.NONE; }
function stub(title, fn) {
validateTitle(title);
validateTestCallback(fn, 0);
var createTest = getCreateTest(baseMode);
var test = createTest(title, fn);
return test;
}
stub.per =
function (params, paramMapper) {
validateParamMapper(paramMapper);
var paramLists = createParamLists(params, paramMapper, baseMode);
var it = createParameterizedTestFunction(paramLists, brand);
return it;
};
stub.when =
function (condition) {
return condition ? it : createUnparameterizedTestFunction(Mode.SKIP, brand);
};
var it = makeParameterizableFunction(stub, function () {
return createUnparameterizedTestFunction(Mode.SKIP, Brand.SKIP_OR_ONLY);
}, function () {
return createUnparameterizedTestFunction(maxMode(Mode.ONLY, baseMode), Brand.SKIP_OR_ONLY);
}, brand);
return it;
}
function getCreateSuite(mode) {
switch (mode) {
default:
return bddDescribe;
case Mode.ONLY:
return bddDescribe.only;
case Mode.SKIP:
return bddDescribe.skip;
}
}
function getCreateTest(mode) {
switch (mode) {
default:
return bddIt;
case Mode.ONLY:
return bddIt.only;
case Mode.SKIP:
return bddXit;
}
}
createBDDInterface.call(this, context, file, mocha);
var bddDescribe = context.describe, bddIt = context.it;
var bddXit = function (title) { return bddIt(title); };
context.describe = context.context =
createUnparameterizedSuiteFunction();
context.xdescribe = context.xcontext =
createUnparameterizedSuiteFunction(Mode.SKIP, Brand.XDESCRIBE);
context.it = context.specify =
createUnparameterizedTestFunction();
context.xit = context.xspecify =
createUnparameterizedTestFunction(Mode.SKIP, Brand.XIT);
context.only =
function (param) { return new ParamInfo(param, Mode.ONLY); };
context.skip =
function (param) { return new ParamInfo(param, Mode.SKIP); };
context.when =
function (condition, param) {
return new ParamInfo(param, condition ? Mode.NORMAL : Mode.SKIP);
};
}
function createParamLists(params, paramMapper, baseMode) {
if (params !== undefined && params !== null) {
var createParamList = function (paramOrParamInfo) {
var _a = getParamAndMode(paramOrParamInfo, baseMode), inParam = _a.param, inMode = _a.mode;
var outParamOrParamInfo = paramMapper ? paramMapper(inParam) : inParam;
var _b = getParamAndMode(outParamOrParamInfo, inMode), outParam = _b.param, outMode = _b.mode;
var paramList = [outParam];
makeParamList(paramList, outMode);
return paramList;
};
var paramLists = Array.prototype.map.call(params, createParamList);
if (paramLists.length)
return paramLists;
}
var message = 'Argument is not a nonempty array-like object.';
throw TypeError(message);
}
function ebdd(suite) {
suite.on('pre-require', createEBDDInterface);
}
function getParamAndMode(paramOrParamInfo, baseMode) {
var param;
var mode;
if (paramOrParamInfo instanceof ParamInfo) {
(param = paramOrParamInfo.param);
var paramInfoMode = paramOrParamInfo.mode;
if (typeof paramInfoMode !== 'number' || !(paramInfoMode in Mode)) {
var message = 'Invalid parameter.';
throw TypeError(message);
}
mode = maxMode(paramInfoMode, baseMode);
}
else {
param = paramOrParamInfo;
mode = baseMode;
}
var paramAndMode = { param: param, mode: mode };
return paramAndMode;
}
function makeParamList(paramList, mode) {
paramList.mode = mode;
}
function makeParameterizableFunction(stub, skip, only, brand) {
switch (brand) {
case Brand.NONE:
break;
case Brand.XIT:
skip = only =
function () {
var message = 'Do not use .skip or .only on a test defined with xit or xspecify.';
throw Error(message);
};
break;
case Brand.XDESCRIBE:
skip = only =
function () {
var message = 'Do not use .skip or .only on a suite defined with xdescribe or xcontext.';
throw Error(message);
};
break;
case Brand.SKIP_OR_ONLY:
skip = only =
function () {
var message = 'Only one of .skip and .only may be specified.';
throw Error(message);
};
break;
}
var descriptors = {
only: { configurable: true, enumerable: true, get: only },
skip: { configurable: true, enumerable: true, get: skip },
};
var parameterizableFn = Object.defineProperties(stub, descriptors);
return parameterizableFn;
}
var maxMode = Math.max;
function multiplyParams(params, paramMapper, baseParamLists) {
var newParamLists = createParamLists(params, paramMapper, Mode.NORMAL);
var paramLists = [];
for (var _i = 0, baseParamLists_3 = baseParamLists; _i < baseParamLists_3.length; _i++) {
var baseParamList = baseParamLists_3[_i];
var baseMode = baseParamList.mode;
for (var _a = 0, newParamLists_1 = newParamLists; _a < newParamLists_1.length; _a++) {
var newParamList = newParamLists_1[_a];
var paramList = __spreadArray(__spreadArray([], baseParamList, true), newParamList, true);
var mode = maxMode(newParamList.mode, baseMode);
makeParamList(paramList, mode);
paramLists.push(paramList);
}
}
return paramLists;
}
function onlyAll(baseParamLists) {
var paramLists = baseParamLists.map(function (baseParamList) {
var paramList = __spreadArray([], baseParamList, true);
var mode = maxMode(Mode.ONLY, baseParamList.mode);
makeParamList(paramList, mode);
return paramList;
});
return paramLists;
}
function skipAll(baseParamLists) {
var paramLists = baseParamLists.map(function (baseParamList) {
var paramList = __spreadArray([], baseParamList, true);
makeParamList(paramList, Mode.SKIP);
return paramList;
});
return paramLists;
}
function validateParamMapper(paramMapper) {
if (paramMapper !== undefined && typeof paramMapper !== 'function') {
var message = 'Argument `paramMapper` is not a function or undefined.';
throw TypeError(message);
}
}
function validateSuiteCallback(fn, expectedLength) {
if (typeof fn !== 'function') {
var message = 'Argument `fn` is not a function.';
throw TypeError(message);
}
var length = fn.length;
if (length !== expectedLength) {
var message = "The suite callback function should accept ".concat(countParameters(expectedLength), ", but it accepts ").concat(length, ".");
throw RangeError(message);
}
}
function validateTestCallback(fn, expectedMinLength) {
if (typeof fn !== 'function') {
var message = 'Argument `fn` is not a function.';
throw TypeError(message);
}
var length = fn.length;
if (length !== expectedMinLength && length !== expectedMinLength + 1) {
var message = "The test callback function should accept ".concat(countParameters(expectedMinLength), ", or ").concat(expectedMinLength + 1, " if it uses a done callback, but it accepts ").concat(length, ".");
throw RangeError(message);
}
}
function validateTitle(title) {
if (typeof title !== 'string') {
var message = 'Argument `title` is not a string.';
throw TypeError(message);
}
}
function validateTitlePattern(titlePattern) {
if (typeof titlePattern !== 'string') {
var message = 'Argument `titlePattern` is not a string.';
throw TypeError(message);
}
}
function defineMocha(attributes) {
Object.defineProperty(self, 'Mocha', attributes);
}
function registerUI() {
Mocha.interfaces.ebdd = ebdd;
}
var installed = false;
if (typeof module !== 'undefined') {
module.exports = ebdd;
installed = true;
}
if (typeof self !== 'undefined') {
if (self.Mocha !== undefined)
registerUI();
else {
defineMocha({
set: function (value) {
if (value !== undefined) {
defineMocha({ value: value, writable: true, enumerable: true });
registerUI();
}
},
configurable: true,
});
}
installed = true;
}
if (!installed) {
var message = 'EBDD failed to set up because no Node.js or browser environment was detected.';
throw new Error(message);
}
})();