UNPKG

ebdd

Version:

Extended BDD interface for Mocha

601 lines (592 loc) 25.6 kB
// 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); } })();