UNPKG

bdd-lazy-var

Version:

Provides "ui" for testing frameworks such as mocha/jasmine which allows to define lazy variables and subjects

809 lines (647 loc) 24 kB
(function (global, factory) { function optional(name) { try { return require(name) } catch(e) {} } typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(optional("mocha")) : typeof define === 'function' && define.amd ? define(['optional!mocha'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Mocha)); }(this, (function (mocha$1) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var mocha__default = /*#__PURE__*/_interopDefaultLegacy(mocha$1); var global$1 = typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}; function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } var indentity = function indentity(x) { return x; }; var symbol = { for: typeof Symbol === 'undefined' ? indentity : Symbol.for }; var LAZY_VARS_FIELD = symbol.for('__lazyVars'); var EXAMPLES_PREFIX = '__SH_EX:'; var VariableMetadata = /*#__PURE__*/function () { function VariableMetadata(name, definition, metadata) { var _this$names; this.value = definition; this.parent = metadata; this.names = (_this$names = {}, _this$names[name] = true, _this$names); } var _proto = VariableMetadata.prototype; _proto.addName = function addName(name) { this.names[name] = true; return this; }; _proto.isNamedAs = function isNamedAs(name) { return this.names[name]; }; _proto.evaluate = function evaluate() { return typeof this.value === 'function' ? this.value() : this.value; }; return VariableMetadata; }(); var Metadata$3 = /*#__PURE__*/function () { Metadata.of = function of(context, varName) { var metadata = context[LAZY_VARS_FIELD]; return varName && metadata ? metadata.defs[varName] : metadata; }; Metadata.ensureDefinedOn = function ensureDefinedOn(context) { if (!context.hasOwnProperty(LAZY_VARS_FIELD)) { context[LAZY_VARS_FIELD] = new Metadata(); } return context[LAZY_VARS_FIELD]; }; function Metadata() { this.defs = {}; this.values = {}; this.hasValues = false; this.defined = false; } var _proto2 = Metadata.prototype; _proto2.getVar = function getVar(name) { if (!this.values.hasOwnProperty(name) && this.defs[name]) { this.hasValues = true; this.values[name] = this.evaluate(name); } return this.values[name]; }; _proto2.evaluate = function evaluate(name) { return this.defs[name].evaluate(); }; _proto2.addChild = function addChild(child) { child.defs = _extends(Object.create(this.defs), child.defs); child.parent = this.defined ? this : this.parent; }; _proto2.addVar = function addVar(name, definition) { if (this.defs.hasOwnProperty(name)) { throw new Error("Cannot define \"" + name + "\" variable twice in the same suite."); } this.defined = true; this.defs[name] = new VariableMetadata(name, definition, this); return this; }; _proto2.addAliasFor = function addAliasFor(name, aliasName) { this.defs[aliasName] = this.defs[name].addName(aliasName); }; _proto2.releaseVars = function releaseVars() { if (this.hasValues) { this.values = {}; this.hasValues = false; } }; _proto2.lookupMetadataFor = function lookupMetadataFor(varName) { var varMeta = this.defs[varName]; var definedIn = varMeta.parent; if (!varMeta || !definedIn.parent.defs[varName]) { throw new Error("Unknown parent variable \"" + varName + "\"."); } return definedIn.parent; }; _proto2.addExamplesFor = function addExamplesFor(name, definition) { var examplesName = EXAMPLES_PREFIX + name; if (this.defs.hasOwnProperty(examplesName)) { throw new Error("Attempt to override \"" + name + "\" shared example"); } return this.addVar(examplesName, definition); }; _proto2.runExamplesFor = function runExamplesFor(name, args) { var examples = this.defs[EXAMPLES_PREFIX + name]; if (!examples) { throw new Error("Attempt to include not defined shared behavior \"" + name + "\""); } return examples.value.apply(examples, args); }; return Metadata; }(); var metadata = { Metadata: Metadata$3 }; var Metadata$2 = metadata.Metadata; var CURRENTLY_RETRIEVED_VAR_FIELD = symbol.for('__currentVariableStack'); var last = function last(array) { return array ? array[array.length - 1] : null; }; var Variable = /*#__PURE__*/function () { Variable.allocate = function allocate(varName, options) { var variable = new this(varName, options.in); return variable.addToStack(); }; Variable.evaluate = function evaluate(varName, options) { if (!options.in) { throw new Error("It looke like you are trying to evaluate \"" + varName + "\" too early. Evaluation context is undefined"); } var variable = Variable.fromStack(options.in); if (variable.isSame(varName)) { return variable.valueInParentContext(varName); } try { variable = Variable.allocate(varName, options); return variable.value(); } finally { variable.pullFromStack(); } }; Variable.fromStack = function fromStack(context) { return last(context[CURRENTLY_RETRIEVED_VAR_FIELD]) || Variable.EMPTY; }; function Variable(varName, context) { this.name = varName; this.context = context; this.evaluationMeta = context ? Metadata$2.of(context) : null; } var _proto = Variable.prototype; _proto.isSame = function isSame(anotherVarName) { return this.name && (this.name === anotherVarName || Metadata$2.of(this.context, this.name).isNamedAs(anotherVarName)); }; _proto.value = function value() { return this.evaluationMeta && this.evaluationMeta.getVar(this.name); }; _proto.addToStack = function addToStack() { this.context[CURRENTLY_RETRIEVED_VAR_FIELD] = this.context[CURRENTLY_RETRIEVED_VAR_FIELD] || []; this.context[CURRENTLY_RETRIEVED_VAR_FIELD].push(this); return this; }; _proto.pullFromStack = function pullFromStack() { this.context[CURRENTLY_RETRIEVED_VAR_FIELD].pop(); }; _proto.valueInParentContext = function valueInParentContext(varOrAliasName) { var meta = this.evaluationMeta; try { this.evaluationMeta = meta.lookupMetadataFor(varOrAliasName); return this.evaluationMeta.evaluate(varOrAliasName); } finally { this.evaluationMeta = meta; } }; return Variable; }(); Variable.EMPTY = new Variable(null, null); var variable = Variable; function parseMessage$1(fn) { var matches = fn.toString().match(/is\.expected\.(\s+(?=\.)|.)+/g); if (!matches) { return ''; } var prefixLength = 'is.expected.'.length; var body = matches.reduce(function (message, chunk) { var cleanChunk = chunk.trim().slice(prefixLength).replace(/[\s.]+/g, ' '); var humanized = humanize$1(cleanChunk).replace(/ and /g, ', '); message.push(humanized); return message; }, []); return "is expected " + body.join(', '); } function humanize$1(value) { return value.replace(/([a-z])([A-Z])/g, function (_, before, letter) { return before + " " + letter.toLowerCase(); }); } var parse_message = { parseMessage: parseMessage$1, humanize: humanize$1 }; var Metadata$1 = metadata.Metadata; var parseMessage = parse_message.parseMessage, humanize = parse_message.humanize; var _interface$1 = function _interface(context, tracker, options) { var get = function get(varName) { return variable.evaluate(varName, { in: tracker.currentContext }); }; get.definitionOf = get.variable = function (varName) { return get.bind(null, varName); }; function def(varName, definition) { var suite = tracker.currentlyDefinedSuite; if (!Array.isArray(varName)) { Metadata$1.ensureDefinedOn(suite).addVar(varName, definition); runHook('onDefineVariable', suite, varName); return; } var name = varName[0], aliases = varName.slice(1); def(name, definition); var metadata = Metadata$1.of(suite); aliases.forEach(function (alias) { metadata.addAliasFor(name, alias); runHook('onDefineVariable', suite, alias); }); } function subject() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } var name = args[0], definition = args[1]; if (args.length === 1) { return def('subject', name); } if (args.length === 2) { return def([name, 'subject'], definition); } return get('subject'); } function sharedExamplesFor(name, defs) { Metadata$1.ensureDefinedOn(tracker.currentlyDefinedSuite).addExamplesFor(name, defs); } function includeExamplesFor(nameOrFn) { var meta = Metadata$1.ensureDefinedOn(tracker.currentlyDefinedSuite); for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { args[_key2 - 1] = arguments[_key2]; } if (typeof nameOrFn === 'function') { nameOrFn.apply(void 0, args); } else { meta.runExamplesFor(nameOrFn, args); } } function itBehavesLike() { for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { args[_key3] = arguments[_key3]; } var nameOrFn = args[0]; var title = typeof nameOrFn === 'function' ? humanize(nameOrFn.name || 'this') : nameOrFn; context.describe("behaves like " + title, function () { includeExamplesFor.apply(void 0, args); }); } var wrapIts = function wrapIts(test) { return function its(prop, messageOrAssert, fn) { var _ref = typeof messageOrAssert === 'function' ? [parseMessage(messageOrAssert), messageOrAssert] : [messageOrAssert, fn], message = _ref[0], assert = _ref[1]; return context.describe(prop, function () { def('__itsSubject__', function () { return prop.split('.').reduce(function (object, field) { var value = object[field]; return typeof value === 'function' ? object[field]() : value; }, subject()); }); test(message || 'is correct', assert); }); }; }; // TODO: `shouldWrapAssert` can be removed when https://github.com/facebook/jest/issues/6516 fixed var wrapIt = function wrapIt(test, shouldWrapAssert) { return function it() { for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { args[_key4] = arguments[_key4]; } if (typeof args[0] === 'function') { args.unshift(parseMessage(args[0])); } if (shouldWrapAssert) { var assert = args[1]; args[1] = function testWrapper() { for (var _len5 = arguments.length, testArgs = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { testArgs[_key5] = arguments[_key5]; } var value = assert.apply(this, testArgs); return value && typeof value.then === 'function' ? value : undefined; }; } return test.apply(void 0, args); }; }; function runHook(name, suite, varName) { if (name && typeof options[name] === 'function') { options[name](suite, varName, context); } } var is = { get expected() { var name = Metadata$1.of(tracker.currentContext, '__itsSubject__') ? '__itsSubject__' : 'subject'; return context.expect(get(name)); } }; return { subject: subject, def: def, get: get, wrapIt: wrapIt, wrapIts: wrapIts, is: is, sharedExamplesFor: sharedExamplesFor, includeExamplesFor: includeExamplesFor, itBehavesLike: itBehavesLike }; }; var Metadata = metadata.Metadata; var SuiteTracker = /*#__PURE__*/function () { function SuiteTracker(config) { if (config === void 0) { config = {}; } this.state = { currentlyDefinedSuite: config.rootSuite, contexts: [config.rootSuite] }; this.suiteTracker = config.suiteTracker; this.suites = []; this.cleanUpCurrentContext = this.cleanUpCurrentContext.bind(this); this.cleanUpCurrentAndRestorePrevContext = this.cleanUpCurrentAndRestorePrevContext.bind(this); } var _proto = SuiteTracker.prototype; _proto.wrapSuite = function wrapSuite(describe) { var tracker = this; return function detectSuite(title, defineTests) { for (var _len = arguments.length, suiteArgs = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { suiteArgs[_key - 2] = arguments[_key]; } return describe.apply(void 0, [title, function defineSuite() { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } tracker.trackSuite(this, defineTests, args); }].concat(suiteArgs)); }; }; _proto.trackSuite = function trackSuite(suite, defineTests, args) { var previousDefinedSuite = this.state.currentlyDefinedSuite; this.defineMetaFor(suite); this.state.currentlyDefinedSuite = suite; this.execute(defineTests, suite, args); this.state.currentlyDefinedSuite = previousDefinedSuite; }; _proto.defineMetaFor = function defineMetaFor(suite) { var meta = Metadata.ensureDefinedOn(suite); var parentMeta = Metadata.of(suite.parent || suite.parentSuite); if (parentMeta) { parentMeta.addChild(meta); } }; _proto.execute = function execute(defineTests, suite, args) { this.suiteTracker.before(this, suite); defineTests.apply(suite, args); if (Metadata.of(suite)) { this.suiteTracker.after(this, suite); } }; _proto.isRoot = function isRoot(suite) { return !(suite.parent ? suite.parent.parent : suite.parentSuite.parentSuite); }; _proto.registerSuite = function registerSuite(context) { this.state.contexts.push(context); }; _proto.cleanUp = function cleanUp(context) { var metadata = Metadata.of(context); if (metadata) { metadata.releaseVars(); } }; _proto.cleanUpCurrentContext = function cleanUpCurrentContext() { this.cleanUp(this.currentContext); }; _proto.cleanUpCurrentAndRestorePrevContext = function cleanUpCurrentAndRestorePrevContext() { this.cleanUpCurrentContext(); this.state.contexts.pop(); }; _createClass(SuiteTracker, [{ key: "currentContext", get: function get() { return this.state.contexts[this.state.contexts.length - 1]; } }, { key: "currentlyDefinedSuite", get: function get() { return this.state.currentlyDefinedSuite; } }]); return SuiteTracker; }(); var suite_tracker = SuiteTracker; function createSuiteTracker$1() { return { before: function before(tracker, suite) { global$1.beforeAll(tracker.registerSuite.bind(tracker, suite)); global$1.afterAll(tracker.cleanUpCurrentAndRestorePrevContext); }, after: function after(tracker) { global$1.beforeAll(tracker.cleanUpCurrentContext); } }; } function addInterface$1(rootSuite, options) { var context = global$1; var tracker = new options.Tracker({ rootSuite: rootSuite, suiteTracker: createSuiteTracker$1() }); var _createLazyVarInterfa = _interface$1(context, tracker, options), wrapIts = _createLazyVarInterfa.wrapIts, wrapIt = _createLazyVarInterfa.wrapIt, ui = _objectWithoutPropertiesLoose(_createLazyVarInterfa, ["wrapIts", "wrapIt"]); var isJest = typeof jest !== 'undefined'; _extends(context, ui); ['', 'x', 'f'].forEach(function (prefix) { var describeKey = prefix + "describe"; var itKey = prefix + "it"; context[itKey + "s"] = wrapIts(context[itKey]); context[itKey] = wrapIt(context[itKey], isJest); context[describeKey] = tracker.wrapSuite(context[describeKey]); context[prefix + "context"] = context[describeKey]; }); context.afterEach(tracker.cleanUpCurrentContext); return ui; } var jasmine = { createUi: function createUi(name, options) { var config = _objectSpread2({ Tracker: suite_tracker }, options); return addInterface$1(global$1.jasmine.getEnv().topSuite(), config); } }; var jest$1 = jasmine; function createSuiteTracker() { return { before: function before(tracker, suite) { suite.beforeAll(tracker.registerSuite.bind(tracker, suite)); }, after: function after(tracker, suite) { suite.beforeAll(tracker.cleanUpCurrentContext); suite.afterAll(tracker.cleanUpCurrentAndRestorePrevContext); } }; } function addInterface(rootSuite, options) { var tracker = new options.Tracker({ rootSuite: rootSuite, suiteTracker: createSuiteTracker() }); var ui; rootSuite.afterEach(tracker.cleanUpCurrentContext); rootSuite.on('pre-require', function (context) { var describe = context.describe, it = context.it; if (!ui) { ui = _interface$1(context, tracker, options); var _ui = ui; _ui.wrapIts; _ui.wrapIt; var restUi = _objectWithoutPropertiesLoose(_ui, ["wrapIts", "wrapIt"]); _extends(context, restUi); } context.its = ui.wrapIts(it); context.its.only = ui.wrapIts(it.only); context.its.skip = ui.wrapIts(it.skip); context.it = ui.wrapIt(it); context.it.only = ui.wrapIt(it.only); context.it.skip = ui.wrapIt(it.skip); context.describe = tracker.wrapSuite(describe); context.describe.skip = tracker.wrapSuite(describe.skip); context.describe.only = tracker.wrapSuite(describe.only); context.context = context.describe; context.xdescribe = context.xcontext = context.describe.skip; }); } var mocha = { createUi: function createUi(name, options) { var config = _objectSpread2({ Tracker: suite_tracker, inheritUi: 'bdd' }, options); mocha__default['default'].interfaces[name] = function (rootSuite) { mocha__default['default'].interfaces[config.inheritUi](rootSuite); return addInterface(rootSuite, config); }; var getters = ['get', 'def', 'subject', 'its', 'it', 'is', 'sharedExamplesFor', 'includeExamplesFor', 'itBehavesLike']; var defs = getters.reduce(function (all, uiName) { all[uiName] = { get: function get() { return global$1[uiName]; } }; return all; }, {}); return Object.defineProperties(mocha__default['default'].interfaces[name], defs); } }; var Mocha; try { Mocha = mocha__default['default']; // eslint-disable-line } catch (e) {// eslint-disable-line } var ui; if (typeof jest !== 'undefined') { ui = jest$1; // eslint-disable-line } else if (global$1.jasmine) { ui = jasmine; // eslint-disable-line } else if (Mocha) { ui = mocha; // eslint-disable-line } if (!ui) { throw new Error("\n Unable to detect testing framework. Make sure that\n * jest, jasmine or mocha is installed\n * bdd-lazy-var is included after \"jasmine\" or \"mocha\"\n "); } var _interface = ui; var prop = symbol.for; var LAZY_VARS_PROP_NAME = prop('__lazyVars'); function defineGetter(context, varName, options) { var params = _objectSpread2({ getterPrefix: '', defineOn: context }, options); var accessorName = params.getterPrefix + varName; var varContext = params.defineOn; var vars = varContext[LAZY_VARS_PROP_NAME] = varContext[LAZY_VARS_PROP_NAME] || {}; if (accessorName in vars) { return; } if (accessorName in varContext) { throw new Error("Cannot create lazy variable \"" + varName + "\" as variable with the same name exists on the provided context"); } vars[accessorName] = true; Object.defineProperty(varContext, accessorName, { configurable: true, get: function get() { return context.get(varName); } }); } var define_var = defineGetter; var bdd_global_var = _interface.createUi('bdd-lazy-var/global', { onDefineVariable: function onDefineVariable(suite, varName, context) { define_var(context, varName, { getterPrefix: '$' }); } }); return bdd_global_var; }))); //# sourceMappingURL=global.js.map