From 007a53f5c1674c20a22ae8da019c223bb1e1e13a Mon Sep 17 00:00:00 2001 From: Sergii Stotskyi Date: Sun, 11 Mar 2018 11:46:15 +0200 Subject: [PATCH] feat(shared-behavior): exports shared behavior related functions (#34) * feat(shared-behavior): exports shared behavior related functions Fixes #26 --- .travis.yml | 1 - getter.js | 86 +++++++++++++++++++++++++----------- global.js | 86 +++++++++++++++++++++++++----------- index.js | 86 +++++++++++++++++++++++++----------- lib/interface.js | 10 ++++- lib/interface/jasmine.js | 10 +---- lib/interface/mocha.js | 18 +++----- lib/shared_behavior.js | 29 ++++++++++++ package.json | 3 +- spec/config.js | 9 ---- spec/shared_behavior_spec.js | 57 ++++++++++++++++++++++++ tools/jasmine.js | 8 ++-- tools/jest.setup.js | 3 +- 13 files changed, 293 insertions(+), 113 deletions(-) create mode 100644 lib/shared_behavior.js create mode 100644 spec/shared_behavior_spec.js diff --git a/.travis.yml b/.travis.yml index 7d511d8..f1b7926 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,4 +12,3 @@ before_script: - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start - sleep 3 - - npm run lint diff --git a/getter.js b/getter.js index 190081e..4d3982b 100644 --- a/getter.js +++ b/getter.js @@ -353,8 +353,49 @@ Variable.EMPTY = new Variable(null, null); var variable = Variable; +var SHARED_EXAMPLES = {}; + +function sharedExamplesFor(name, defs) { + if (SHARED_EXAMPLES[name]) { + throw new Error('Attempt to override "' + name + '" shared example'); + } + + SHARED_EXAMPLES[name] = defs; +} + +function includeExamplesFor(name) { + if (!SHARED_EXAMPLES.hasOwnProperty(name)) { + throw new Error('Attempt to include not defined shared behavior "' + name + '"'); + } + + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + SHARED_EXAMPLES[name].apply(null, args); +} + +function itBehavesLike(name) { + for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } + + commonjsGlobal.describe('behaves like ' + name, function () { + includeExamplesFor.apply(undefined, [name].concat(args)); + }); +} + +var shared_behavior = { + sharedExamplesFor: sharedExamplesFor, + includeExamplesFor: includeExamplesFor, + itBehavesLike: itBehavesLike +}; + var _interface$2 = createCommonjsModule(function (module) { var Metadata = metadata.Metadata; + var sharedExamplesFor = shared_behavior.sharedExamplesFor, + includeExamplesFor = shared_behavior.includeExamplesFor, + itBehavesLike = shared_behavior.itBehavesLike; module.exports = function (context, tracker, options) { @@ -418,7 +459,14 @@ var _interface$2 = createCommonjsModule(function (module) { } } - return { subject: subject, def: def, get: get$$1 }; + return { + subject: subject, + def: def, + get: get$$1, + sharedExamplesFor: sharedExamplesFor, + includeExamplesFor: includeExamplesFor, + itBehavesLike: itBehavesLike + }; }; }); @@ -571,7 +619,7 @@ function addInterface(rootSuite, options) { context.fdescribe = tracker.wrapSuite(context.fdescribe); commonjsGlobal.afterEach(tracker.cleanUpCurrentContext); - return context; + return ui; } var jasmine = { @@ -580,13 +628,7 @@ var jasmine = { Tracker: suite_tracker }, options); - var context = addInterface(commonjsGlobal.jasmine.getEnv().topSuite(), config); - - return { - get: context.get, - def: context.def, - subject: context.subject - }; + return addInterface(commonjsGlobal.jasmine.getEnv().topSuite(), config); } }; @@ -636,23 +678,15 @@ var mocha$1 = { return addInterface$1(rootSuite, config); }; - return Object.defineProperties(mocha.interfaces[name], { - get: { - get: function get$$1() { - return commonjsGlobal.get; - } - }, - def: { - get: function get$$1() { - return commonjsGlobal.def; - } - }, - subject: { - get: function get$$1() { - return commonjsGlobal.subject; - } - } - }); + var getters = ['get', 'def', 'subject', 'sharedExamplesFor', 'includeExamplesFor', 'itBehavesLike']; + var defs = getters.reduce(function (all, uiName) { + all[uiName] = { get: function get$$1() { + return commonjsGlobal[uiName]; + } }; + return all; + }, {}); + + return Object.defineProperties(mocha.interfaces[name], defs); } }; diff --git a/global.js b/global.js index efeb557..fc451f6 100644 --- a/global.js +++ b/global.js @@ -353,8 +353,49 @@ Variable.EMPTY = new Variable(null, null); var variable = Variable; +var SHARED_EXAMPLES = {}; + +function sharedExamplesFor(name, defs) { + if (SHARED_EXAMPLES[name]) { + throw new Error('Attempt to override "' + name + '" shared example'); + } + + SHARED_EXAMPLES[name] = defs; +} + +function includeExamplesFor(name) { + if (!SHARED_EXAMPLES.hasOwnProperty(name)) { + throw new Error('Attempt to include not defined shared behavior "' + name + '"'); + } + + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + SHARED_EXAMPLES[name].apply(null, args); +} + +function itBehavesLike(name) { + for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } + + commonjsGlobal.describe('behaves like ' + name, function () { + includeExamplesFor.apply(undefined, [name].concat(args)); + }); +} + +var shared_behavior = { + sharedExamplesFor: sharedExamplesFor, + includeExamplesFor: includeExamplesFor, + itBehavesLike: itBehavesLike +}; + var _interface$2 = createCommonjsModule(function (module) { var Metadata = metadata.Metadata; + var sharedExamplesFor = shared_behavior.sharedExamplesFor, + includeExamplesFor = shared_behavior.includeExamplesFor, + itBehavesLike = shared_behavior.itBehavesLike; module.exports = function (context, tracker, options) { @@ -418,7 +459,14 @@ var _interface$2 = createCommonjsModule(function (module) { } } - return { subject: subject, def: def, get: get$$1 }; + return { + subject: subject, + def: def, + get: get$$1, + sharedExamplesFor: sharedExamplesFor, + includeExamplesFor: includeExamplesFor, + itBehavesLike: itBehavesLike + }; }; }); @@ -571,7 +619,7 @@ function addInterface(rootSuite, options) { context.fdescribe = tracker.wrapSuite(context.fdescribe); commonjsGlobal.afterEach(tracker.cleanUpCurrentContext); - return context; + return ui; } var jasmine = { @@ -580,13 +628,7 @@ var jasmine = { Tracker: suite_tracker }, options); - var context = addInterface(commonjsGlobal.jasmine.getEnv().topSuite(), config); - - return { - get: context.get, - def: context.def, - subject: context.subject - }; + return addInterface(commonjsGlobal.jasmine.getEnv().topSuite(), config); } }; @@ -636,23 +678,15 @@ var mocha$1 = { return addInterface$1(rootSuite, config); }; - return Object.defineProperties(mocha.interfaces[name], { - get: { - get: function get$$1() { - return commonjsGlobal.get; - } - }, - def: { - get: function get$$1() { - return commonjsGlobal.def; - } - }, - subject: { - get: function get$$1() { - return commonjsGlobal.subject; - } - } - }); + var getters = ['get', 'def', 'subject', 'sharedExamplesFor', 'includeExamplesFor', 'itBehavesLike']; + var defs = getters.reduce(function (all, uiName) { + all[uiName] = { get: function get$$1() { + return commonjsGlobal[uiName]; + } }; + return all; + }, {}); + + return Object.defineProperties(mocha.interfaces[name], defs); } }; diff --git a/index.js b/index.js index dc8752c..7ba4fb1 100644 --- a/index.js +++ b/index.js @@ -353,8 +353,49 @@ Variable.EMPTY = new Variable(null, null); var variable = Variable; +var SHARED_EXAMPLES = {}; + +function sharedExamplesFor(name, defs) { + if (SHARED_EXAMPLES[name]) { + throw new Error('Attempt to override "' + name + '" shared example'); + } + + SHARED_EXAMPLES[name] = defs; +} + +function includeExamplesFor(name) { + if (!SHARED_EXAMPLES.hasOwnProperty(name)) { + throw new Error('Attempt to include not defined shared behavior "' + name + '"'); + } + + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + SHARED_EXAMPLES[name].apply(null, args); +} + +function itBehavesLike(name) { + for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } + + commonjsGlobal.describe('behaves like ' + name, function () { + includeExamplesFor.apply(undefined, [name].concat(args)); + }); +} + +var shared_behavior = { + sharedExamplesFor: sharedExamplesFor, + includeExamplesFor: includeExamplesFor, + itBehavesLike: itBehavesLike +}; + var _interface$2 = createCommonjsModule(function (module) { var Metadata = metadata.Metadata; + var sharedExamplesFor = shared_behavior.sharedExamplesFor, + includeExamplesFor = shared_behavior.includeExamplesFor, + itBehavesLike = shared_behavior.itBehavesLike; module.exports = function (context, tracker, options) { @@ -418,7 +459,14 @@ var _interface$2 = createCommonjsModule(function (module) { } } - return { subject: subject, def: def, get: get$$1 }; + return { + subject: subject, + def: def, + get: get$$1, + sharedExamplesFor: sharedExamplesFor, + includeExamplesFor: includeExamplesFor, + itBehavesLike: itBehavesLike + }; }; }); @@ -571,7 +619,7 @@ function addInterface(rootSuite, options) { context.fdescribe = tracker.wrapSuite(context.fdescribe); commonjsGlobal.afterEach(tracker.cleanUpCurrentContext); - return context; + return ui; } var jasmine = { @@ -580,13 +628,7 @@ var jasmine = { Tracker: suite_tracker }, options); - var context = addInterface(commonjsGlobal.jasmine.getEnv().topSuite(), config); - - return { - get: context.get, - def: context.def, - subject: context.subject - }; + return addInterface(commonjsGlobal.jasmine.getEnv().topSuite(), config); } }; @@ -636,23 +678,15 @@ var mocha$1 = { return addInterface$1(rootSuite, config); }; - return Object.defineProperties(mocha.interfaces[name], { - get: { - get: function get$$1() { - return commonjsGlobal.get; - } - }, - def: { - get: function get$$1() { - return commonjsGlobal.def; - } - }, - subject: { - get: function get$$1() { - return commonjsGlobal.subject; - } - } - }); + var getters = ['get', 'def', 'subject', 'sharedExamplesFor', 'includeExamplesFor', 'itBehavesLike']; + var defs = getters.reduce(function (all, uiName) { + all[uiName] = { get: function get$$1() { + return commonjsGlobal[uiName]; + } }; + return all; + }, {}); + + return Object.defineProperties(mocha.interfaces[name], defs); } }; diff --git a/lib/interface.js b/lib/interface.js index 4d4166f..c0298dc 100644 --- a/lib/interface.js +++ b/lib/interface.js @@ -1,5 +1,6 @@ const { Metadata } = require('./metadata'); const Variable = require('./variable'); +const { sharedExamplesFor, includeExamplesFor, itBehavesLike } = require('./shared_behavior'); module.exports = (context, tracker, options) => { const get = varName => Variable.evaluate(varName, { in: tracker.currentContext }); @@ -45,5 +46,12 @@ module.exports = (context, tracker, options) => { } } - return { subject, def, get }; + return { + subject, + def, + get, + sharedExamplesFor, + includeExamplesFor, + itBehavesLike + }; }; diff --git a/lib/interface/jasmine.js b/lib/interface/jasmine.js index c20dc1d..dc409df 100644 --- a/lib/interface/jasmine.js +++ b/lib/interface/jasmine.js @@ -25,7 +25,7 @@ function addInterface(rootSuite, options) { context.fdescribe = tracker.wrapSuite(context.fdescribe); global.afterEach(tracker.cleanUpCurrentContext); - return context; + return ui; } module.exports = { @@ -34,12 +34,6 @@ module.exports = { Tracker: SuiteTracker, }, options); - const context = addInterface(global.jasmine.getEnv().topSuite(), config); - - return { - get: context.get, - def: context.def, - subject: context.subject - }; + return addInterface(global.jasmine.getEnv().topSuite(), config); } }; diff --git a/lib/interface/mocha.js b/lib/interface/mocha.js index d53f7a1..25413f8 100644 --- a/lib/interface/mocha.js +++ b/lib/interface/mocha.js @@ -44,16 +44,12 @@ module.exports = { return addInterface(rootSuite, config); }; - return Object.defineProperties(Mocha.interfaces[name], { - get: { - get: () => global.get - }, - def: { - get: () => global.def - }, - subject: { - get: () => global.subject - } - }); + const getters = ['get', 'def', 'subject', 'sharedExamplesFor', 'includeExamplesFor', 'itBehavesLike']; + const defs = getters.reduce((all, uiName) => { + all[uiName] = { get: () => global[uiName] }; + return all; + }, {}); + + return Object.defineProperties(Mocha.interfaces[name], defs); } }; diff --git a/lib/shared_behavior.js b/lib/shared_behavior.js new file mode 100644 index 0000000..e1a0dd0 --- /dev/null +++ b/lib/shared_behavior.js @@ -0,0 +1,29 @@ +const SHARED_EXAMPLES = {}; + +function sharedExamplesFor(name, defs) { + if (SHARED_EXAMPLES[name]) { + throw new Error(`Attempt to override "${name}" shared example`); + } + + SHARED_EXAMPLES[name] = defs; +} + +function includeExamplesFor(name, ...args) { + if (!SHARED_EXAMPLES.hasOwnProperty(name)) { + throw new Error(`Attempt to include not defined shared behavior "${name}"`); + } + + SHARED_EXAMPLES[name].apply(null, args); +} + +function itBehavesLike(name, ...args) { + global.describe(`behaves like ${name}`, () => { + includeExamplesFor(name, ...args); + }); +} + +module.exports = { + sharedExamplesFor, + includeExamplesFor, + itBehavesLike +}; diff --git a/package.json b/package.json index 4b5f22f..ea25023 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "rollup-plugin-commonjs": "^8.2.6" }, "scripts": { - "mocha": "NODE_PATH=. mocha -r spec/config -r spec/interface_examples -r spec/default_suite_tracking_examples", + "mocha": "NODE_PATH=. mocha -r spec/config spec/*_examples.js spec/shared_behavior_spec.js", "test.mocha-ui": "npm run mocha -- -u index.js spec/interface_spec.js", "test.mocha-global": "npm run mocha -- -u global.js spec/global_defs_spec.js", "test.mocha-getter": "npm run mocha -- -u getter.js spec/getter_defs_spec.js", @@ -74,6 +74,7 @@ "test.jest-getter": "jest --findRelatedTests spec/getter_defs_spec.js getter.js", "test.jest": "npm run test.jest-ui && npm run test.jest-global && npm run test.jest-getter", "test": "npm run test.mocha && npm run test.mocha-in-browser && npm run test.jasmine && npm run test.jasmine-in-browser && npm run test.jest", + "prebuild": "npm run lint", "build.ui": "rollup -c tools/rollup.umd.js -i lib/interface/dialects/bdd.js -o index.js", "build.global-ui": "rollup -c tools/rollup.umd.js -i lib/interface/dialects/bdd_global_var.js -o global.js", "build.getter-ui": "rollup -c tools/rollup.umd.js -i lib/interface/dialects/bdd_getter_var.js -o getter.js", diff --git a/spec/config.js b/spec/config.js index 126e92e..0d233d7 100644 --- a/spec/config.js +++ b/spec/config.js @@ -10,15 +10,6 @@ global.expect = chai.expect; global.spy = chai.spy; - var examples = {}; - global.sharedExamplesFor = function(name, defs) { - examples[name] = defs; - }; - - global.includeExamplesFor = function(name) { - examples[name].apply(this, Array.prototype.slice.call(arguments, 1)); - }; - if (global.beforeAll) { global.before = global.beforeAll; } diff --git a/spec/shared_behavior_spec.js b/spec/shared_behavior_spec.js new file mode 100644 index 0000000..4acdead --- /dev/null +++ b/spec/shared_behavior_spec.js @@ -0,0 +1,57 @@ +describe('Shared behavior', function() { + describe('`sharedExamplesFor`', function() { + it('throws error when trying to redefine existing shared examples', function() { + sharedExamplesFor('__test', function() {}); + + expect(function() { + sharedExamplesFor('__test') + }).to.throw(/Attempt to override/) + }); + }); + + describe('`includeExamplesFor`', function() { + it('throws error when trying to include non-existing shared examples', function() { + expect(function() { + includeExamplesFor('__non_existing') + }).to.throw(/not defined shared behavior/) + }); + + it('calls registered shared examples', function() { + var examples = spy(); + + sharedExamplesFor('__call', examples); + includeExamplesFor('__call'); + + expect(examples).to.have.been.called(); + }); + + it('passes all arguments to shared examples', function() { + var examples = spy(); + var args = [{}, {}]; + + sharedExamplesFor('__arguments', examples); + includeExamplesFor('__arguments', args[0], args[1]); + + expect(examples).to.have.been.called.with.exactly(args[0], args[1]); + }); + }); + + describe('`itBehavesLike`', function() { + it('includes examples in a nested context', function() { + var examples = spy(); + var args = [{}, {}]; + + sharedExamplesFor('__Collection', examples); + spy.on(global, 'describe', function(name, fn) { + fn(); + }); + + itBehavesLike('__Collection', args[0], args[1]); + + expect(global.describe).to.have.been.called.with('behaves like __Collection'); + expect(examples).to.have.been.called.with.exactly(args[0], args[1]); + + spy.restore(global, 'describe'); + }); + }); +}); diff --git a/tools/jasmine.js b/tools/jasmine.js index 6c3e128..f4b7ffa 100644 --- a/tools/jasmine.js +++ b/tools/jasmine.js @@ -3,15 +3,17 @@ const JasmineCli = require('jasmine'); const jasmine = new JasmineCli(); const helpers = [ '../spec/config', - '../spec/default_suite_tracking_examples', - '../spec/interface_examples', `../${process.argv[2]}` ]; helpers.forEach(require); jasmine.loadConfig({ spec_dir: 'spec', - spec_files: process.argv.slice(3), + spec_files: [ + 'interface_examples.js', + 'default_suite_tracking_examples.js', + 'shared_behavior_spec.js' + ].concat(process.argv.slice(3)), }); jasmine.execute(); diff --git a/tools/jest.setup.js b/tools/jest.setup.js index fe7e113..abdc0c6 100644 --- a/tools/jest.setup.js +++ b/tools/jest.setup.js @@ -1,6 +1,7 @@ const uiFile = process.argv.slice(0).pop(); require('../spec/config'); +require(`../${uiFile}`); require('../spec/interface_examples'); require('../spec/default_suite_tracking_examples'); -require(`../${uiFile}`); +require('../spec/shared_behavior_spec');