diff --git a/karma.conf.js b/karma.conf.js index d0a7683..782da3a 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -55,6 +55,7 @@ module.exports = (config) => { reporters: [ 'mocha' ], files: [ + 'node_modules/es6-shim/es6-shim.js', 'tests.webpack.js' ], diff --git a/modules/Expectation.js b/modules/Expectation.js index 6db296f..240d395 100644 --- a/modules/Expectation.js +++ b/modules/Expectation.js @@ -6,9 +6,11 @@ import { isA, isFunction, isArray, + isSet, isEqual, isObject, functionThrows, + setContains, arrayContains, objectContains, stringContains @@ -286,6 +288,8 @@ class Expectation { if (isArray(this.actual)) { contains = arrayContains(this.actual, value, compareValues) + } else if (isSet(this.actual)) { + contains = setContains(this.actual, value, compareValues) } else if (isObject(this.actual)) { contains = objectContains(this.actual, value, compareValues) } else if (typeof this.actual === 'string') { @@ -320,6 +324,8 @@ class Expectation { if (isArray(this.actual)) { contains = arrayContains(this.actual, value, compareValues) + } else if (isSet(this.actual)) { + contains = setContains(this.actual, value, compareValues) } else if (isObject(this.actual)) { contains = objectContains(this.actual, value, compareValues) } else if (typeof this.actual === 'string') { diff --git a/modules/TestUtils.js b/modules/TestUtils.js index 7d7ea31..6638d70 100644 --- a/modules/TestUtils.js +++ b/modules/TestUtils.js @@ -27,6 +27,29 @@ export const isFunction = (object) => export const isArray = (object) => Array.isArray(object) + +const hasSet = typeof Set === 'function' && Set.prototype +const setSizeDescriptor = Object.getOwnPropertyDescriptor && hasSet ? + Object.getOwnPropertyDescriptor(Set.prototype, 'size') : null +const setSize = hasSet && setSizeDescriptor && typeof setSizeDescriptor.get === 'function' + ? setSizeDescriptor.get : null + +/** + * Returns true if the given object is a set. + */ +export const isSet = (object) => { + if (!setSize) { + return false + } + try { + setSize.call(object) + return true + } catch (err) { + return false + } +} + + /** * Returns true if the given object is an object. */ @@ -88,6 +111,20 @@ export const functionThrows = (fn, context, args, value) => { export const arrayContains = (array, value, compareValues) => array.some(item => compareValues(item, value) !== false) +/** + * Returns true if the given array contains the value, false + * otherwise. The compareValues function must return false to + * indicate a non-match. + */ +export const setContains = (set, value, compareValues) => { + for (let item of set) { + if (compareValues(value, item)) { + return true + } + } + return false +} + const ownEnumerableKeys = (object) => { if (typeof Reflect === 'object' && typeof Reflect.ownKeys === 'function') { return Reflect.ownKeys(object) diff --git a/modules/__tests__/toExclude-test.js b/modules/__tests__/toExclude-test.js index 40a10a2..9b69fd0 100644 --- a/modules/__tests__/toExclude-test.js +++ b/modules/__tests__/toExclude-test.js @@ -1,7 +1,7 @@ import expect from '../index' describe('toExclude', () => { - it('requires the actual value to be an array or string', () => { + it('requires the actual value to be an array, object or string', () => { expect(() => { expect(1).toExclude(2) }).toThrow(/must be an array, object, or a string/) @@ -19,9 +19,21 @@ describe('toExclude', () => { }).toThrow(/to exclude/) }) + it('does not throw when a set does not contain the expected value', () => { + expect(() => { + expect(new Set([ 1, 2, 3 ])).toExclude(4) + }).toNotThrow() + }) + + it('throws when a set contains the expected value', () => { + expect(() => { + expect(new Set([ 1, 2, 3 ])).toExclude(2) + }).toThrow(/to exclude/) + }) + it('throws when an object contains an expected object', () => { expect(() => { - expect({ a: 1 }).toExclude({ a: 1 }) + expect( { a: 1 }).toExclude({ a: 1 }) }).toThrow(/to exclude/) }) @@ -31,13 +43,19 @@ describe('toExclude', () => { }).toNotThrow() }) + it('does not throw when a set contains an unexpected object', () => { + expect(() => { + expect(new Set([ { a: 1 } ])).toExclude({ b: 2 }) + }).toNotThrow() + }) + it('does not throw when an object contains an expected object with an unexpected value', () => { expect(() => { expect({ a: 1 }).toExclude({ a: 2 }) }).toNotThrow() }) - it('does not throw when an array does not contain the expected value', () => { + it('does not throw when a string does not contain the expected value', () => { expect(() => { expect('hello world').toExclude('goodbye') }).toNotThrow() diff --git a/modules/__tests__/toInclude-test.js b/modules/__tests__/toInclude-test.js index bfec6eb..dfb789c 100644 --- a/modules/__tests__/toInclude-test.js +++ b/modules/__tests__/toInclude-test.js @@ -19,7 +19,19 @@ describe('toInclude', () => { expect([ { a: 1 }, { c: 2 } ]).toInclude({ c: 2 }) }).toNotThrow() }) - + + it('does not throw when a set contains an expected integer', () => { + expect(() => { + expect(new Set([ 1, 2, 3 ])).toInclude(2) + }).toNotThrow() + }) + + it('does not throw when a set contains an expected object', () => { + expect(() => { + expect(new Set([ { a: 1 }, { c: 2} ])).toInclude({ c: 2 }) + }).toNotThrow() + }) + it('does not throw when an object contains an expected object', () => { expect(() => { expect({ a: 1, b: 2, c: 3 }).toInclude({ b: 2 }) @@ -118,6 +130,18 @@ describe('toInclude', () => { }).toThrow(/to include/) }) + it('throws when a set does not contain an expected integer', () => { + expect(() => { + expect(new Set([ 1, 2, 3 ])).toInclude(4) + }).toThrow(/to include/) + }) + + it('throws when a set does not contain an expected object', () => { + expect(() => { + expect(new Set([ { a: 1 }, { c: 2 } ])).toInclude({ a: 2 }) + }).toThrow(/to include/) + }) + it('does not throw when a string contains the expected value', () => { expect(() => { expect('hello world').toInclude('world') diff --git a/package.json b/package.json index a6f66d3..fdd0e03 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "babel-eslint": "^6.1.2", "babel-loader": "^6.2.4", "babel-preset-es2015": "^6.6.0", + "es6-shim": "^0.35.2", "eslint": "^3.2.2", "eslint-plugin-import": "^1.12.0", "gzip-size": "^3.0.0",