diff --git a/.gitignore b/.gitignore index d23365d..67ccce4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,60 +1,3 @@ -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - +node_modules/ .idea/ - -## File-based project format: -*.iws -*.iml - -## Plugin-specific files: - -# IntelliJ -/out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -### Node template -# Logs -logs -*.log -npm-debug.log* - -# Runtime data -pids -*.pid -*.seed - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules -jspm_packages - -# Optional npm cache directory -.npm - -# Optional REPL history -.node_repl_history - +dist/ diff --git a/.travis.yml b/.travis.yml index c4688cf..2d13975 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ before_install: before_script: - npm prune script: - - istanbul cover ./node_modules/.bin/_mocha --report lcovonly -- -R spec + - node build && istanbul cover ./node_modules/.bin/_mocha --report lcovonly -- -R spec - codecov after_success: - 'curl -Lo travis_after_all.py https://git.io/travis_after_all' diff --git a/build.js b/build.js new file mode 100644 index 0000000..3587c2e --- /dev/null +++ b/build.js @@ -0,0 +1,39 @@ +const rollup = require('rollup') +const commonjs = require('rollup-plugin-commonjs') +const babel = require('rollup-plugin-babel') + +rollup.rollup({ + entry: 'src/index.js', + external: [ + 'sinon', + 'fluent-arguments', + 'ramda/src/compose', + 'ramda/src/curry', + 'ramda/src/filter', + 'ramda/src/forEach' + ], + plugins: [ + commonjs(), + babel({ + presets: [ + ['env', { + modules: false, + targets: {node: 4} + }] + ], + plugins: [ + 'ramda', + 'external-helpers' + ] + }) + ] +}).then(bundle => { + bundle.write({ + dest: 'dist/index.js', + format: 'cjs' + }) + bundle.write({ + dest: 'dist/index.mjs', + format: 'es' + }) +}) diff --git a/package.json b/package.json index c453975..9c69ec0 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,12 @@ "description": "Create easily configurable sinon stubs that mimic constructors and keep track of their instances", "author": "Lukas Taegert ", "license": "MIT", - "main": "src/index.js", + "main": "dist/index.js", + "module": "dist/index.mjs", + "jsnext:main": "dist/index.mjs", + "files": [ + "dist" + ], "config": { "validate-commit-msg": { "types": [ @@ -36,25 +41,32 @@ "sinon": ">=1.15.0" }, "dependencies": { - "fluent-arguments": ">= 1.0.6", - "ramda": ">= 0.23.0" + "fluent-arguments": "^1.0.7", + "ramda": "^0.23.0" }, "devDependencies": { + "babel-plugin-external-helpers": "^6.22.0", + "babel-plugin-ramda": "^1.2.0", + "babel-preset-env": "^1.5.1", "chai": "^4.0.0", "codecov": "^2.2.0", "husky": "^0.13.3", "istanbul": "^0.4.5", "lint-staged": "^3.5.0", "mocha": "^3.4.2", + "rollup": "^0.41.6", + "rollup-plugin-babel": "^2.7.1", + "rollup-plugin-commonjs": "^8.0.2", + "rollup-plugin-node-resolve": "^3.0.0", "semantic-release": "^6.3.6", - "standard": "^10.0.2", "sinon": "^2.3.2", + "standard": "^10.0.2", "validate-commit-msg": "^2.12.1" }, "scripts": { - "test": "mocha", + "test": "node build && mocha", "lint": "standard", - "semantic-release": "semantic-release pre && npm publish && semantic-release post", + "semantic-release": "npm install && node build && semantic-release pre && npm publish && semantic-release post", "precommit": "lint-staged", "commitmsg": "validate-commit-msg", "prepush": "npm test", diff --git a/src/constructors.js b/src/constructors.js index ee48de0..40166f6 100644 --- a/src/constructors.js +++ b/src/constructors.js @@ -1,31 +1,27 @@ -var R = require('ramda') -var fa = require('fluent-arguments') +import fa from 'fluent-arguments' +import R from 'ramda' -function getArrayFromArrayLikeObject (args) { - return Array.prototype.slice.call(args) -} +const getArrayFromArrayLikeObject = args => Array.prototype.slice.call(args) -var isMethod = R.curry(function (object, propName) { - return !Object.getOwnPropertyDescriptor(object, propName).get && - typeof object[propName] === 'function' && !(propName === 'constructor') -}) +const isMethod = R.curry((object, propName) => +!Object.getOwnPropertyDescriptor(object, propName).get && +typeof object[propName] === 'function' && +!(propName === 'constructor')) -var applyToEachFunctionKeyInObject = function (appliedFunction, object) { - R.compose( - R.forEach(appliedFunction), - R.filter(isMethod(object)) - )(Object.getOwnPropertyNames(object)) -} +const applyToEachFunctionKeyInObject = (appliedFunction, object) => R.compose( + R.forEach(appliedFunction), + R.filter(isMethod(object)) +)(Object.getOwnPropertyNames(object)) -var applyToEachFunctionKeyInPrototypeChain = function (appliedFunction, object) { +const applyToEachFunctionKeyInPrototypeChain = (appliedFunction, object) => { if (object) { applyToEachFunctionKeyInObject(appliedFunction, object) applyToEachFunctionKeyInPrototypeChain(appliedFunction, Object.getPrototypeOf(object)) } } -var getInstanceIndexWithValidation = function (index, numInstances) { - var instanceIndex = index || 0 +const getInstanceIndexWithValidation = (index, numInstances) => { + const instanceIndex = index || 0 if (typeof index === 'undefined') { if (numInstances > 1) { @@ -40,56 +36,44 @@ var getInstanceIndexWithValidation = function (index, numInstances) { return instanceIndex } -module.exports = function getStubOrSpyConstructor (getConstructorProperties) { - return function (Target) { - var constructorProps = getConstructorProperties(Target) - var instances = [] - var instanceArgs = [] - var methodParams = [] - var afterCreation - - function StubOrSpyConstructor () { - constructorProps.SourceConstructor.apply(this, arguments) - instanceArgs.push(getArrayFromArrayLikeObject(arguments)) - instances.push(this) - - Target && applyToEachFunctionKeyInPrototypeChain( - constructorProps.processMethodOfInstance(this), constructorProps.getInstanceMethodNameSource(this)) - methodParams.forEach(constructorProps.configureMethodOfInstance(this)) - afterCreation && afterCreation(this) - } - - StubOrSpyConstructor.prototype = constructorProps.SourceConstructor.prototype +export default getConstructorProperties => Target => { + const constructorProps = getConstructorProperties(Target) + const instances = [] + const instanceArgs = [] + let methodParams = [] + let afterCreation + + function StubOrSpyConstructor () { + constructorProps.SourceConstructor.apply(this, arguments) + instanceArgs.push(getArrayFromArrayLikeObject(arguments)) + instances.push(this) + + Target && applyToEachFunctionKeyInPrototypeChain( + constructorProps.processMethodOfInstance(this), constructorProps.getInstanceMethodNameSource(this)) + methodParams.forEach(constructorProps.configureMethodOfInstance(this)) + afterCreation && afterCreation(this) + } - function configureMethods (methods) { - methodParams = methods - return this - } + StubOrSpyConstructor.prototype = constructorProps.SourceConstructor.prototype - StubOrSpyConstructor[constructorProps.configureMethodsKey] = fa.createFunc(configureMethods) + StubOrSpyConstructor[constructorProps.configureMethodsKey] = fa.createFunc(function (methods) { + methodParams = methods + return this + }) - StubOrSpyConstructor.afterCreation = function (onAfterCreation) { - afterCreation = onAfterCreation - return this - } + StubOrSpyConstructor.afterCreation = function (onAfterCreation) { + afterCreation = onAfterCreation + return this + } - StubOrSpyConstructor.getInstances = function () { - return instances - } + StubOrSpyConstructor.getInstances = () => instances - StubOrSpyConstructor.getInstance = function (index) { - return instances[getInstanceIndexWithValidation(index, instances.length)] - } + StubOrSpyConstructor.getInstance = index => instances[getInstanceIndexWithValidation(index, instances.length)] - StubOrSpyConstructor.getInstancesArgs = function () { - return instanceArgs - } + StubOrSpyConstructor.getInstancesArgs = () => instanceArgs - StubOrSpyConstructor.getInstanceArgs = function (index) { - return instanceArgs[getInstanceIndexWithValidation(index, instances.length)] - } + StubOrSpyConstructor.getInstanceArgs = index => instanceArgs[getInstanceIndexWithValidation(index, instances.length)] - Target && applyToEachFunctionKeyInObject(constructorProps.processMethodOfConstructor(StubOrSpyConstructor), Target) - return StubOrSpyConstructor - } + Target && applyToEachFunctionKeyInObject(constructorProps.processMethodOfConstructor(StubOrSpyConstructor), Target) + return StubOrSpyConstructor } diff --git a/src/index.js b/src/index.js index 7ccb5a7..add55c9 100644 --- a/src/index.js +++ b/src/index.js @@ -1,39 +1,40 @@ -var getStubOrSpyConstructor = require('./constructors') -var R = require('ramda') -var fa = require('fluent-arguments') -var sinon = require('sinon') -var ARG_RETURN_VAL = 'returnVal' -var ARG_RETURN_THIS = 'returnThis' +import fa from 'fluent-arguments' +import R from 'ramda' +import sinon from 'sinon' +import getStubOrSpyConstructor from './constructors' -var setMethodToStub = R.curry(function (object, methodName) { +const ARG_RETURN_VAL = 'returnVal' +const ARG_RETURN_THIS = 'returnThis' + +const setMethodToStub = R.curry((object, methodName) => { object[methodName] = sinon.stub() }) -function configureStub (object, params) { +const configureStub = (object, params) => { if (params.hasOwnProperty(ARG_RETURN_THIS)) { object[params.value].returnsThis() } else if (params.hasOwnProperty(ARG_RETURN_VAL)) { object[params.value].returns(params[ARG_RETURN_VAL]) } } -var setMethodToStubWithParams = R.curry(function (object, params) { +const setMethodToStubWithParams = R.curry((object, params) => { setMethodToStub(object, params.value) configureStub(object, params) }) -var stubMethodWithParams = R.curry(function (object, params) { +const stubMethodWithParams = R.curry((object, params) => { object[params.value] && object[params.value].restore && object[params.value].restore() sinon.stub(object, params.value) configureStub(object, params) }) -var spyOnMethod = R.curry(function (object, methodName) { +const spyOnMethod = R.curry((object, methodName) => { if (!(object[methodName] && object[methodName].isSinonProxy)) { sinon.spy(object, methodName) } }) -var copyAndSpyOnMethod = R.curry(function (object, source, methodName) { +const copyAndSpyOnMethod = R.curry((object, source, methodName) => { if (source[methodName].isSinonProxy) { object[methodName] = source[methodName] } else { @@ -41,39 +42,33 @@ var copyAndSpyOnMethod = R.curry(function (object, source, methodName) { } }) -function getStubConstructorProperties (Target) { - return { - SourceConstructor: function () {}, - processMethodOfInstance: setMethodToStub, - getInstanceMethodNameSource: function () { return Target.prototype }, - processMethodOfConstructor: function (TheConstructor) { return setMethodToStub(TheConstructor) }, - configureMethodsKey: 'withMethods', - configureMethodOfInstance: setMethodToStubWithParams - } -} +const getStubConstructorProperties = Target => ({ + SourceConstructor: function () {}, + processMethodOfInstance: setMethodToStub, + getInstanceMethodNameSource: () => Target.prototype, + processMethodOfConstructor: TheConstructor => setMethodToStub(TheConstructor), + configureMethodsKey: 'withMethods', + configureMethodOfInstance: setMethodToStubWithParams +}) -function getSpyConstructorProperties (Target) { - return { - SourceConstructor: Target, - processMethodOfInstance: spyOnMethod, - getInstanceMethodNameSource: function (instance) { return instance }, - processMethodOfConstructor: function (TheConstructor) { return copyAndSpyOnMethod(TheConstructor, Target) }, - configureMethodsKey: 'withStubs', - configureMethodOfInstance: stubMethodWithParams - } -} +const getSpyConstructorProperties = Target => ({ + SourceConstructor: Target, + processMethodOfInstance: spyOnMethod, + getInstanceMethodNameSource: instance => instance, + processMethodOfConstructor: TheConstructor => copyAndSpyOnMethod(TheConstructor, Target), + configureMethodsKey: 'withStubs', + configureMethodOfInstance: stubMethodWithParams +}) -function getMethodStubs (methodParams) { +function getMethodStubsHandler (methodParams) { var result = {} methodParams.forEach(setMethodToStubWithParams(result)) return result } -module.exports = { - getStubConstructor: getStubOrSpyConstructor(getStubConstructorProperties), - getSpyConstructor: getStubOrSpyConstructor(getSpyConstructorProperties), - getMethodStubs: fa.createFunc(getMethodStubs), - returning: fa.createArg({args: [ARG_RETURN_VAL], extendsPrevious: true}), - returningThis: fa.createArg({extra: {returnThis: true}, extendsPrevious: true}) -} +export const getStubConstructor = getStubOrSpyConstructor(getStubConstructorProperties) +export const getSpyConstructor = getStubOrSpyConstructor(getSpyConstructorProperties) +export const getMethodStubs = fa.createFunc(getMethodStubsHandler) +export const returning = fa.createArg({args: [ARG_RETURN_VAL], extendsPrevious: true}) +export const returningThis = fa.createArg({extra: {returnThis: true}, extendsPrevious: true}) diff --git a/test/index.spec.js b/test/index.spec.js index 2ea7c03..d0b3f64 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -1,7 +1,7 @@ /* eslint-env mocha */ /* eslint-disable no-unused-expressions,no-new */ -var sinonHelpers = require('../src/index') +var sinonHelpers = require('../dist/index') var getStubConstructor = sinonHelpers.getStubConstructor var getSpyConstructor = sinonHelpers.getSpyConstructor var getMethodStubs = sinonHelpers.getMethodStubs