diff --git a/package.json b/package.json index 43374d7..5cfe349 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "clean": "rimraf lib", "lint": "eslint src test", "prepublish": "npm run test && npm run build", - "test": "npm run lint && babel-node test/index", + "test": "npm run lint && babel-node node_modules/.bin/check-compose src/utils/compose.js && babel-node test/index", "transpile": "babel src --out-dir lib" }, "repository": { @@ -36,6 +36,7 @@ "homepage": "https://github.com/stampit-org/react-stamp#readme", "dependencies": { "lodash": "^4.6.1", + "stamp-specification": "^1.0.5", "stamp-utils": "^1.2.4" }, "devDependencies": { @@ -45,6 +46,7 @@ "babel-loader": "^6.2.4", "babel-preset-es2015": "^6.6.0", "babel-preset-stage-2": "^6.5.0", + "check-compose": "^1.0.0", "eslint": "~2.2.0", "react": "^0.14.7", "react-addons-test-utils": "^0.14.7", diff --git a/src/utils/compose.js b/src/utils/compose.js index 6927bea..e48513e 100644 --- a/src/utils/compose.js +++ b/src/utils/compose.js @@ -1,19 +1,30 @@ import assign from 'lodash/assign'; -import forEach from 'lodash/forEach'; -import merge from 'lodash/merge'; -import { isStamp } from 'stamp-utils'; +import isFunction from 'lodash/isFunction'; +import isObject from 'lodash/isObject'; +import mergeWith from 'lodash/mergeWith'; +//import compose from 'stamp-specification'; import { parseDesc, wrapMethods, } from './'; +const isDescriptor = isObject; +const merge = (dst, src) => mergeWith(dst, src, (dstValue, srcValue) => { + if (Array.isArray(dstValue)) { + if (Array.isArray(srcValue)) return dstValue.concat(srcValue); + if (isObject(srcValue)) return merge({}, srcValue); + } + + return undefined; +}); + /** * Given a description object, return a stamp aka composable. * * (desc?: SpecDesc) => Stamp */ -function createStamp (specDesc = {}) { +function createStamp (specDesc = {}, composeFunction) { const Component = (options, ...args) => { let instance = Object.create(specDesc.methods || {}); @@ -32,52 +43,67 @@ function createStamp (specDesc = {}) { return instance; }; - merge(Component, specDesc.deepStaticProperties); + merge(Component, specDesc.staticDeepProperties); assign(Component, specDesc.staticProperties); Object.defineProperties(Component, specDesc.staticPropertyDescriptors || {}); !Component.displayName && (Component.displayName = 'Component'); + const composeImplementation = isFunction(Component.compose) ? Component.compose : composeFunction; + Component.compose = function () { + return composeImplementation.apply(this, arguments); + }; + assign(Component.compose, specDesc); + return Component; } /** - * Take any number of stamps or descriptors. Return a new stamp - * that encapsulates combined behavior. If nothing is passed in, - * an empty stamp is returned. - * - * (...args?: Stamp|ReactDesc|SpecDesc[]) => Stamp + * Mutates the dstDescriptor by merging the srcComposable data into it. + * @param {object} dstDescriptor The descriptor object to merge into. + * @param {object} [srcComposable] The composable (either descriptor or stamp) to merge data form. + * @returns {object} Returns the dstDescriptor argument. */ -export default function compose (...args) { - const descs = args.map(arg => parseDesc(arg)); - const compDesc = {}; - - isStamp(this) && descs.unshift(this.compose); - - forEach(descs, desc => { - const { - initializers, methods, properties, staticProperties, propertyDescriptors, - staticPropertyDescriptors, deepProperties, deepStaticProperties, configuration, - } = desc; +function mergeComposable (dstDescriptor, srcComposable) { + const srcDescriptor = parseDesc(srcComposable && srcComposable.compose || srcComposable); + if (!isDescriptor(srcDescriptor)) return dstDescriptor; + + const combineProperty = (propName, action) => { + if (!isObject(srcDescriptor[propName])) return; + if (!isObject(dstDescriptor[propName])) dstDescriptor[propName] = {}; + action(dstDescriptor[propName], srcDescriptor[propName]); + }; - // Wrap React lifecycle methods - compDesc.methods = wrapMethods(compDesc.methods, methods); + console.log(dstDescriptor.methods); + combineProperty('methods', wrapMethods); // Wrap React lifecycle methods - // Stamp spec - compDesc.initializers = (compDesc.initializers || []).concat(initializers) - .filter(initializer => typeof initializer === 'function'); + //console.log(dstDescriptor.methods); - forEach({ properties, staticProperties, propertyDescriptors, staticPropertyDescriptors }, - (val, key) => val && (compDesc[key] = assign(compDesc[key] || {}, val)) - ); + combineProperty('properties', assign); + combineProperty('deepProperties', merge); + combineProperty('propertyDescriptors', assign); + combineProperty('staticProperties', assign); + combineProperty('staticDeepProperties', merge); + combineProperty('staticPropertyDescriptors', assign); + combineProperty('configuration', assign); + combineProperty('deepConfiguration', merge); + if (Array.isArray(srcDescriptor.initializers)) { + if (!Array.isArray(dstDescriptor.initializers)) dstDescriptor.initializers = []; + dstDescriptor.initializers.push.apply(dstDescriptor.initializers, srcDescriptor.initializers.filter(isFunction)); + } - forEach({ deepProperties, deepStaticProperties, configuration }, - (val, key) => val && (compDesc[key] = merge(compDesc[key] || {}, val)) - ); - }); + //console.log(dstDescriptor); - const stamp = createStamp(compDesc); - stamp.compose = assign(compose.bind(stamp), compDesc); + return dstDescriptor; +} - return stamp; +/** + * Given the list of composables (stamp descriptors and stamps) returns a new stamp (composable factory function). + * @param {...(object|Function)} [composables] The list of composables. + * @returns {Function} A new stamp (aka composable factory function). + */ +export default function compose (...composables) { + const descriptor = [this].concat(composables).filter(isObject).reduce(mergeComposable, {}); + //console.log(descriptor); + return createStamp(descriptor, compose); } diff --git a/src/utils/descriptor.js b/src/utils/descriptor.js index 0fd1019..6f11224 100644 --- a/src/utils/descriptor.js +++ b/src/utils/descriptor.js @@ -1,18 +1,31 @@ import forEach from 'lodash/forEach'; -import isEmpty from 'lodash/isEmpty'; -import { isDescriptor, isStamp } from 'stamp-utils'; +import has from 'lodash/has'; + +function isSpecDescriptor (obj) { + const properties = [ + 'methods', + 'properties', + 'deepProperties', + 'propertyDescriptors', + 'staticProperties', + 'staticDeepProperties', + 'staticPropertyDescriptors', + 'initializers', + 'configuration', + 'deepConfiguration' + ]; + + return properties.filter(property => has(obj, property)).length; +} /** * Create a stamp spec compliant desc object. * - * (desc?: Stamp | ReactDesc | SpecDesc) => SpecDesc + * (desc?: ReactDesc | SpecDesc) => SpecDesc */ export default function parseDesc (desc = {}) { - if (isStamp(desc)) { - return desc.compose; - } else if (isDescriptor(desc) || isEmpty(desc)) { - return desc; - } + //console.log(desc); + if (isSpecDescriptor(desc)) return desc; let { displayName, init, state, statics, @@ -21,14 +34,16 @@ export default function parseDesc (desc = {}) { } = desc; const parsedDesc = {}; + //console.log(methods); + displayName && (parsedDesc.staticProperties = { displayName }); init && (parsedDesc.initializers = [ init ]); state && (parsedDesc.deepProperties = { state }); methods && (parsedDesc.methods = methods); - parsedDesc.deepStaticProperties = { ...statics }; + parsedDesc.staticDeepProperties = { ...statics }; forEach({ contextTypes, childContextTypes, propTypes, defaultProps }, - (val, key) => val && (parsedDesc.deepStaticProperties[key] = val) + (val, key) => val && (parsedDesc.staticDeepProperties[key] = val) ); return parsedDesc; diff --git a/src/utils/react.js b/src/utils/react.js index 0125d41..ff6ce28 100644 --- a/src/utils/react.js +++ b/src/utils/react.js @@ -24,6 +24,8 @@ const lifecycle = { * (targ?: Object, src?: Object) => new: Object */ export default function wrapMethods (targ = {}, src = {}) { + //console.log(targ); + //console.log(src); const methods = mapValues(src, (val, key) => { switch (lifecycle[key]) { case 'wrap': @@ -51,5 +53,5 @@ export default function wrapMethods (targ = {}, src = {}) { } }); - return assign({ ...targ }, methods); + return assign(targ, methods); } diff --git a/test/compose.js b/test/compose.js index 6ec01a8..f23c7d3 100644 --- a/test/compose.js +++ b/test/compose.js @@ -129,49 +129,15 @@ test('composing objects with methods', (t) => { t.plan(4); const obj1 = { - state: { - stamp: false, - mixin: false, - }, - - getChildContext () { - return { - foo: true, - bar: false, - }; - }, - componentDidMount () { this.state.stamp = true; }, - - shouldComponentUpdate () { - return true; - }, - - render () { - return false; - }, }; const obj2 = { - getChildContext () { - return { - bar: true, - }; - }, - componentDidMount () { this.state.mixin = true; }, - - shouldComponentUpdate () { - return false; - }, - - render () { - return true; - }, }; const stamp = compose(obj1, obj2); diff --git a/test/index.js b/test/index.js index 3d2f0b1..688c0ae 100644 --- a/test/index.js +++ b/test/index.js @@ -1,4 +1,3 @@ -import './spec'; import './basics'; import './state'; import './statics'; diff --git a/test/spec/assignment-tests.js b/test/spec/assignment-tests.js deleted file mode 100644 index eb0f45a..0000000 --- a/test/spec/assignment-tests.js +++ /dev/null @@ -1,80 +0,0 @@ -import test from 'tape'; -import { compose } from '../../src/utils'; - -const assignmentProps = [ - 'methods', - 'properties', - 'deepProperties', - 'staticProperties', - 'deepStaticProperties' -]; - -const build = (num) => { - const composable = function () {}; - composable.compose = function () {}; - - assignmentProps.forEach(prop => { - composable.compose[prop] = { - [num]: num, - override: num - }; - }); - - return composable; -}; - -// Loop over each property that is copied by assignment and ensure -// that copy and priority are implemented correctly. -assignmentProps.forEach(prop => { - test(`${ prop } assignment 1`, (assert) => { - const subject = compose(build(1), build(2)); - const props = subject.compose; - - const actual = props[prop][1]; - const expected = 1; - - assert.equal(actual, expected, - `${ prop } should be copied by assignment from first argument`); - - assert.end(); - }); - - test(`${ prop } assignment 2`, (assert) => { - const subject = compose(build(1), build(2)); - const props = subject.compose; - - const actual = props[prop][2]; - const expected = 2; - - assert.equal(actual, expected, - `${ prop } should be copied by assignment from 2nd argument`); - - assert.end(); - }); - - test(`${ prop } assignment 3`, (assert) => { - const subject = compose(build(1), build(2), build(3)); - const props = subject.compose; - - const actual = props[prop][3]; - const expected = 3; - - assert.equal(actual, expected, - `${ prop } should be copied by assignment from subsequent arguments`); - - assert.end(); - }); - - test(`${ prop } assignment priority`, (assert) => { - const subject = compose(build(1), build(2)); - const props = subject.compose; - - const actual = props[prop].override; - const expected = 2; - - assert.equal(actual, expected, - `${ prop } should be copied by assignment with last-in priority`); - - assert.end(); - }); -}); diff --git a/test/spec/compose-basic-tests.js b/test/spec/compose-basic-tests.js deleted file mode 100644 index 43f9d14..0000000 --- a/test/spec/compose-basic-tests.js +++ /dev/null @@ -1,67 +0,0 @@ -import test from 'tape'; -import { compose } from '../../src/utils'; - -test('compose function', assert => { - const actual = typeof compose; - const expected = 'function'; - - assert.equal(actual, expected, - 'compose should be a function.'); - - assert.end(); -}); - -test('compose.staticProperties', nest => { - ['staticProperties', 'deepStaticProperties'].forEach(descriptorName => { - - nest.test('...for descriptor', assert => { - const actual = compose({ - [ descriptorName ]: { - a: 'a' - } - }, { - [ descriptorName ]: { - b: 'b' - } - }).compose[ descriptorName ]; - - const expected = { - a: 'a', - b: 'b' - }; - - assert.deepEqual(actual, expected, - `should compose ${ descriptorName } into descriptor`); - - assert.end(); - }); - - nest.test('...for stamp', assert => { - const stamp = compose({ - [ descriptorName ]: { - a: 'a' - } - }, { - [ descriptorName ]: { - b: 'b' - } - }); - - const actual = Object.assign({}, { - a: stamp.a, - b: stamp.b - }); - - const expected = { - a: 'a', - b: 'b' - }; - - assert.deepEqual(actual, expected, - `should add ${ descriptorName } to stamp`); - - assert.end(); - }); - - }); -}); diff --git a/test/spec/descriptor-tests.js b/test/spec/descriptor-tests.js deleted file mode 100644 index 9c51766..0000000 --- a/test/spec/descriptor-tests.js +++ /dev/null @@ -1,72 +0,0 @@ -import test from 'tape'; -import { compose } from '../../src/utils'; - -test('comopose function pojo (Plain Old JavaScript Object)', nest => { - const objDescriptors = [ - 'properties', - 'deepProperties', - 'staticProperties', - 'deepStaticProperties', - 'propertyDescriptors', - 'staticPropertyDescriptors', - 'configuration' - ]; - - objDescriptors.forEach(descriptorName => { - nest.test(`...with pojo descriptor.${ descriptorName }`, assert => { - const descriptor = { - [ descriptorName ]: { - a: { - b: 'b' - } - } - }; - - const actual = compose(descriptor).compose[ descriptorName ].a; - const expected = { b: 'b' }; - - assert.deepEqual(actual, expected, - `should create ${ descriptorName } descriptor`); - - assert.end(); - }); - }); - -}); - -test('compose function pojo', nest => { - - nest.test('...with pojo descriptor.methods', assert => { - const a = function a () { - return 'a'; - }; - - const actual = Object.getPrototypeOf(compose({ - methods: { a } - })()); - - const expected = { a }; - - assert.deepEqual(actual, expected, - 'should create methods descriptor'); - - assert.end(); - }); - - nest.test('...with pojo descriptor.initializers', assert => { - const a = function a () { - return 'a'; - }; - - const actual = compose({ - initializers: [ a ] - }).compose.initializers; - - const expected = [ a ]; - - assert.deepEqual(actual, expected, - 'should create initializers descriptor'); - - assert.end(); - }); -}); diff --git a/test/spec/index.js b/test/spec/index.js deleted file mode 100644 index bfe2f71..0000000 --- a/test/spec/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import './assignment-tests'; -import './compose-basic-tests'; -import './descriptor-tests'; -import './initializer-tests'; -import './merge-tests'; -import './priority-tests'; -import './property-descriptor-tests'; -import './stamp-tests'; -import './instance-replacement-tests'; -import './property-safety-tests.js'; diff --git a/test/spec/initializer-tests.js b/test/spec/initializer-tests.js deleted file mode 100644 index 8ea5be2..0000000 --- a/test/spec/initializer-tests.js +++ /dev/null @@ -1,187 +0,0 @@ -import test from 'tape'; -import { compose } from '../../src/utils'; - - -const build = (num) => { - - const composable = function () {}; - composable.compose = function () {}; - composable.compose.initializers = [() => { - return {num}; - }]; - - return composable; -}; - -const buildInitializers = () => { - - const composable = function () {}; - composable.compose = function () {}; - composable.compose.initializers = [ - (options, { instance }) => { - return Object.assign(instance, { - a: 'a', - override: 'a' - }); - }, - (options, { instance }) => { - return Object.assign(instance, { - b: 'b' - }); - }, - (options, { instance }) => { - return Object.assign(instance, { - override: 'c' - }); - } - ]; - return composable; -}; - - -test('compose()', nest => { - - nest.test('...with no initializers', assert => { - const subject = compose({ initializers: [ 0, 'a', null, undefined, {}, NaN, /regexp/ ]}); - const initializers = subject.compose.initializers; - - assert.notOk(initializers && initializers.length, - 'should not add any initializers'); - - assert.end(); - }); - - nest.test('...with two initializers', assert => { - const subject = compose(build(1), build(2)); - const initializers = subject.compose.initializers; - - const actual = initializers[0]().num; - const expected = 1; - - assert.equal(actual, expected, - 'should add initializer from first composable'); - - assert.end(); - }); - - nest.test('...with two initializers', assert => { - const subject = compose(build(1), build(2)); - const initializers = subject.compose.initializers; - - const actual = initializers[1]().num; - const expected = 2; - - assert.equal(actual, expected, - 'should add initializer from second composable'); - - assert.end(); - }); - - nest.test('...with three initializers', assert => { - const subject = compose(build(1), build(2), build(3)); - const initializers = subject.compose.initializers; - - const actual = initializers[2]().num; - const expected = 3; - - assert.equal(actual, expected, - 'should add initializer from subsequent composables'); - - assert.end(); - }); -}); - -test('stamp()', nest => { - - nest.test('...with initializers', assert => { - const composable = function () {}; - composable.compose = function () {}; - composable.compose.properties = { - 'instanceProps': true - }; - composable.compose.initializers = [ - function ({ stampOption }, { instance, stamp, args }) { - const actual = { - correctThisValue: this === instance, - hasOptions: Boolean(stampOption), - hasInstance: Boolean(instance.instanceProps), - hasStamp: Boolean(stamp.compose), - argsLength: args.length === 3 - }; - - const expected = { - correctThisValue: true, - hasOptions: true, - hasInstance: true, - hasStamp: true, - argsLength: true - }; - - assert.deepEqual(actual, expected, - 'should call initializer with correct signature'); - - assert.end(); - } - ]; - const testStamp = compose(composable); - - testStamp({stampOption: true}, 1, 2); - }); - - nest.test('...with overrides in initializer', assert => { - const stamp = buildInitializers(); - - const actual = compose(stamp)(); - const expected = { - a: 'a', - b: 'b', - override: 'c' - }; - - assert.deepEqual(actual, expected, - 'should apply initializers with last-in priority'); - - assert.end(); - }); - - nest.test('...with args in initializer', assert => { - const expected = [0, 'string', { obj: {} }, [1, 2, 3]]; - - const composable = function () {}; - composable.compose = function () {}; - composable.compose.initializers = [ - function (options, { args }) { - assert.deepEqual(args, expected, - 'should receive all given arguments'); - - assert.end(); - } - ]; - const testStamp = compose(composable); - - testStamp(expected[0], expected[1], expected[2], expected[3]); - }); - - nest.test('...with `this` in initializer', assert => { - const composable = function () {}; - composable.compose = function () {}; - composable.compose.initializers = [ - function () { - return Object.assign(this, { - a: 'a' - }); - } - ]; - const stamp = compose(composable); - - const actual = compose(stamp)(); - const expected = { - a: 'a' - }; - - assert.deepEqual(actual, expected, - 'should use object instance as `this` inside initializers'); - - assert.end(); - }); -}); diff --git a/test/spec/instance-replacement-tests.js b/test/spec/instance-replacement-tests.js deleted file mode 100644 index 0580acd..0000000 --- a/test/spec/instance-replacement-tests.js +++ /dev/null @@ -1,66 +0,0 @@ -import test from 'tape'; -import { compose } from '../../src/utils'; - -[0, 1, null, NaN, 'string', true, false].forEach(obj => { - test('initializer returns ' + obj, assert => { - compose({ - initializers: [ - () => { - return obj; - }, - (options, { instance }) => { - const actual = typeof instance; - const expected = typeof obj; - - assert.equal(actual, expected, - 'initializer return value should replace instance'); - - assert.end(); - } - ] - })(); - }); -}); - - -test('initializer returns undefined', assert => { - compose({ - initializers: [ - () => { - return undefined; - }, - (options, { instance }) => { - const actual = typeof instance; - const expected = 'object'; - - assert.equal(actual, expected, - 'initializer return value should not replace instance'); - - assert.end(); - } - ] - })(); -}); - -test('instance replacement', assert => { - const message = 'instance replaced'; - const newInstance = { - message: message - }; - - const obj = compose({ - initializers: [ - () => { - return newInstance; - } - ] - })(); - - const actual = obj.message; - const expected = message; - - assert.equal(actual, expected, - 'the replaced instance value should be returned from the stamp'); - - assert.end(); -}); diff --git a/test/spec/merge-tests.js b/test/spec/merge-tests.js deleted file mode 100644 index 89c1e74..0000000 --- a/test/spec/merge-tests.js +++ /dev/null @@ -1,95 +0,0 @@ -import test from 'tape'; -import { compose } from '../../src/utils'; - -const mergeProps = [ - 'deepProperties', - 'deepStaticProperties', - 'configuration' -]; - - -const build = (num) => { - const composable = function () {}; - composable.compose = function () {}; - - mergeProps.forEach(prop => { - composable.compose[prop] = { - a: { - [num]: num, - merge: { - [num]: num - } - } - }; - }); - - return composable; -}; - -test('Deep property merge', nest => { - - // Loop over each property that is merged and ensure - // that merge implemented correctly. - mergeProps.forEach(prop => { - - nest.test(`...${ prop } merge 1`, (assert) => { - const subject = compose(build(1), build(2)); - const props = subject.compose; - - const actual = props[prop].a[1]; - const expected = 1; - - assert.equal(actual, expected, - `${ prop } should be merged from first argument`); - - assert.end(); - }); - - nest.test(`...${ prop } merge 2`, (assert) => { - const subject = compose(build(1), build(2)); - const props = subject.compose; - - const actual = props[prop].a[2]; - const expected = 2; - - assert.equal(actual, expected, - `${ prop } should be merged from 2nd argument`); - - assert.end(); - }); - - nest.test(`...${ prop } merge 3`, (assert) => { - const subject = compose(build(1), build(2), build(3)); - const props = subject.compose; - - const actual = props[prop].a[3]; - const expected = 3; - - assert.equal(actual, expected, - `${ prop } should be merged from subsequent arguments`); - - assert.end(); - }); - - nest.test(`...${ prop } merge collision`, (assert) => { - const actual = compose( - { - deepProperties: { - a: { b: 1} - } - }, - { - deepProperties: { - a: { b: 2 } - } - })(); - const expected = { a: { b: 2 } }; - - assert.deepEqual(actual, expected, - `${ prop } conflicts should be merged with last-in priority.`); - - assert.end(); - }); - - }); -}); diff --git a/test/spec/priority-tests.js b/test/spec/priority-tests.js deleted file mode 100644 index 9c4e693..0000000 --- a/test/spec/priority-tests.js +++ /dev/null @@ -1,94 +0,0 @@ -import test from 'tape'; -import { compose } from '../../src/utils'; - -const buildDescriptor = (obj) => { - return Object.assign({}, { - properties: { - a: 'props', - b: 'props' - } - }, obj); -}; - -test('compose override priorities', nest => { - nest.test('...with instance', assert => { - const stamp = compose(buildDescriptor()); - const actual = stamp({ instance: { - a: 'instance' - }}).a; - const expected = 'props'; - - assert.equal(actual, expected, - 'properties should override instance props'); - - assert.end(); - }); - - nest.test('...with deepProperties', assert => { - const stamp = compose( - buildDescriptor({ - deepProperties: { - a: 'deepProps' - } - })); - const actual = stamp().a; - const expected = 'props'; - - assert.equal(actual, expected, - 'shallow properties should override deep properties'); - - assert.end(); - }); - - nest.test('...with descriptors', assert => { - const stamp = compose( - buildDescriptor({ - propertyDescriptors: { - b: { - value: 'propertyDescriptors' - } - } - })); - - const actual = stamp().b; - const expected = 'propertyDescriptors'; - - assert.equal(actual, expected, - 'descriptors should override shallow properties'); - assert.end(); - }); - - nest.test('...with instance & deepProperties', assert => { - const stamp = compose(buildDescriptor({ - deepProperties: { - c: 'deep' - } - })); - const actual = stamp({ instance: { - c: 'instance' - }}).c; - const expected = 'deep'; - - assert.equal(actual, expected, - 'deepProperties should override instance props'); - - assert.end(); - }); - - nest.test('...with staticProperties', assert => { - const stamp = compose({ - deepStaticProperties: { - d: 'deep' - }, - staticProperties: { - d: 'staticProps' - } - }); - const actual = stamp.d; - const expected = 'staticProps'; - - assert.equal(actual, expected, - 'staticProperties should override deepStaticProperties'); - assert.end(); - }); -}); diff --git a/test/spec/property-descriptor-tests.js b/test/spec/property-descriptor-tests.js deleted file mode 100644 index 0d5718e..0000000 --- a/test/spec/property-descriptor-tests.js +++ /dev/null @@ -1,74 +0,0 @@ -import test from 'tape'; -import { compose } from '../../src/utils'; - -const createDescriptors = () => { - const a = { - value: 'a', - writable: false, - configurable: false, - enumerable: false - }; - const b = Object.assign({}, a); - const descriptors = { - a, - b - }; - return descriptors; -}; - -test('stamp', nest => { - nest.test('...with propertyDescriptors', assert => { - const descriptors = createDescriptors(); - const b = descriptors.b; - - const obj = compose({ - propertyDescriptors: Object.assign({}, descriptors) - })(); - - const actual = Object.getOwnPropertyDescriptor(obj, 'b'); - const expected = Object.assign({}, b); - - assert.deepEqual(actual, expected, - 'should assign propertyDescriptors to instances'); - - assert.end(); - }); - - nest.test('...with propertyDescriptors and existing prop conflict', assert => { - const descriptors = createDescriptors(); - - const obj = compose({ - properties: { - a: 'existing prop' - } - }, - { - propertyDescriptors: Object.assign({}, descriptors) - })(); - - const actual = obj.a; - const expected = 'a'; - - assert.deepEqual(actual, expected, - 'should assign propertyDescriptors to instances & override existing prop'); - - assert.end(); - }); - - nest.test('...with staticPropertyDescriptors', assert => { - const descriptors = createDescriptors(); - const b = descriptors.b; - - const stamp = compose({ - staticPropertyDescriptors: Object.assign({}, descriptors) - }); - - const actual = Object.getOwnPropertyDescriptor(stamp, 'b'); - const expected = Object.assign({}, b); - - assert.deepEqual(actual, expected, - 'should assign staticProperties to stamp'); - - assert.end(); - }); -}); diff --git a/test/spec/property-safety-tests.js b/test/spec/property-safety-tests.js deleted file mode 100644 index e779a4d..0000000 --- a/test/spec/property-safety-tests.js +++ /dev/null @@ -1,62 +0,0 @@ -import test from 'tape'; -import { compose } from '../../src/utils'; - -test('Deep properties', nest => { - nest.test('...should be cloned for descriptors', assert => { - const deepInstance = { e: 'deep' }; - const stamp = compose({ - deepProperties: { - obj: deepInstance - } - }); - const actual = stamp.compose.deepProperties.obj; - - assert.notEqual(actual, deepInstance, - 'deepProperties should not be assigned between descriptors'); - assert.end(); - }); - - nest.test('...should be cloned for instances', assert => { - const stamp = compose({ - deepProperties: { - obj: { e: 'deep' } - } - }); - const notExpected = stamp.compose.deepProperties.obj; - const actual = stamp().obj; - - assert.notEqual(actual, notExpected, - 'deepProperties should not be assigned from descriptor to object instance'); - assert.end(); - }); -}); - -test('Deep static properties', nest => { - nest.test('...should be cloned for descriptors', assert => { - const deepInstance = { e: 'deep' }; - const stamp = compose({ - deepStaticProperties: { - obj: deepInstance - } - }); - const actual = stamp.compose.deepStaticProperties.obj; - - assert.notEqual(actual, deepInstance, - 'deepStaticProperties should not be assigned between descriptors'); - assert.end(); - }); - - nest.test('...should be cloned for new stamps', assert => { - const stamp = compose({ - deepStaticProperties: { - obj: { e: 'deep' } - } - }); - const notExpected = stamp.compose.deepStaticProperties.obj; - const actual = stamp.obj; - - assert.notEqual(actual, notExpected, - 'deepStaticProperties should not be assigned from descriptor to stamp'); - assert.end(); - }); -}); diff --git a/test/spec/stamp-tests.js b/test/spec/stamp-tests.js deleted file mode 100644 index c640b62..0000000 --- a/test/spec/stamp-tests.js +++ /dev/null @@ -1,98 +0,0 @@ -import test from 'tape'; -import { compose } from '../../src/utils'; - -const build = (prop, key, val = key) => { - const composable = function () {}; - composable.compose = function () {}; - - composable.compose[prop] = { - [val]: val - }; - - return composable; -}; - -test('compose()', assert => { - const actual = typeof compose(); - const expected = 'function'; - - assert.equal(actual, expected, - 'compose() should return a function'); - - assert.end(); -}); - - -test('Stamp', nest => { - nest.test('...with no arguments', assert => { - const actual = typeof compose()(); - const expected = 'object'; - - assert.equal(actual, expected, - 'should produce an object instance'); - - assert.end(); - }); -}); - -test('Stamp assignments', nest => { - nest.test('...with properties', assert => { - const composable = function () {}; - composable.compose = function () {}; - composable.compose.properties = { - a: 'a', - b: 'b' - }; - const stamp = compose(composable); - - const actual = stamp(); - const expected = { - a: 'a', - b: 'b' - }; - - assert.deepEqual(actual, expected, - 'should create properties'); - - assert.end(); - }); -}); - -test('Stamp.compose()', nest => { - nest.test('...type', assert => { - const actual = typeof compose().compose; - const expected = 'function'; - - assert.equal(actual, expected, - 'should be a function'); - - assert.end(); - }); - - nest.test('...with no arguments', assert => { - const actual = typeof compose().compose().compose; - const expected = 'function'; - - assert.equal(actual, expected, - 'should return a new stamp'); - - assert.end(); - }); - - nest.test('...with base defaults', assert => { - const stamp1 = compose(build('properties', 'a')); - const stamp2 = compose(build('properties', 'b')); - const finalStamp = stamp1.compose(stamp2); - - const actual = finalStamp(); - const expected = { - a: 'a', - b: 'b' - }; - - assert.deepEqual(actual, expected, - 'should use Stamp as base composable'); - - assert.end(); - }); -});