-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add toIncludeKeys and toExcludeKeys #87
Changes from 4 commits
4904d23
d967938
23cabe5
1cff71c
f09aa9d
bd1ddd7
a812b2e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -286,6 +286,32 @@ expect('hello world').toExclude('goodbye') | |
expect('hello world').toNotContain('goodbye') | ||
``` | ||
|
||
### toIncludeKeys | ||
> `expect(object).toIncludeKeys(keys, [comparator], [message])`<br> | ||
> `expect(object).toIncludeKey(keys, [comparator], [message])`<br> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's change the first argument name to |
||
> `expect(object).toContainKeys(keys, [comparator], [message])`<br> | ||
> `expect(object).toContainKey(keys, [comparator], [message])` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
|
||
Asserts that the given `object` (may be an array, or a function, or anything with keys) contains *all* of the provided keys. The optional parameter `comparator` is a function which if given an object and a string key, it should return a boolean detailing whether or not the key exists in the object. By default, a shallow check with `Object.prototype.hasOwnProperty` is performed. | ||
|
||
```js | ||
expect({ a: 1 }).toIncludeKey('a') | ||
expect({ a: 1, b: 2 }).toIncludeKeys([ 'a', 'b' ]) | ||
``` | ||
|
||
### toExcludeKeys | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
> `expect(object).toExcludeKeys(keys, [comparator], [message])`<br> | ||
> `expect(object).toExcludeKey(keys, [comparator], [message])`<br> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
> `expect(object).toNotContainKeys(keys, [comparator], [message])`<br> | ||
> `expect(object).toNotContainKey(keys, [comparator], [message])` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
|
||
Asserts that the given `object` (may be an array, or a function, or anything with keys) does not contain *any* of the provided keys. The optional parameter `comparator` is a function which if given an object and a string key, it should return a boolean detailing whether or not the key exists in the object. By default, a shallow check with `Object.prototype.hasOwnProperty` is performed. | ||
|
||
```js | ||
expect({ a: 1 }).toExcludeKey('b') | ||
expect({ a: 1, b: 2 }).toExcludeKey([ 'c', 'd' ]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would we use |
||
``` | ||
|
||
### (spy) toHaveBeenCalled | ||
|
||
> `expect(spy).toHaveBeenCalled([message])` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,8 @@ import { | |
isArray, | ||
isObject, | ||
isFunction, | ||
isA | ||
isA, | ||
containKeysHelper | ||
} from './TestUtils' | ||
|
||
/** | ||
|
@@ -364,6 +365,42 @@ class Expectation { | |
return this | ||
} | ||
|
||
toIncludeKeys(keys, comparator, message) { | ||
if (typeof comparator === 'string') { | ||
message = comparator | ||
comparator = null | ||
} | ||
|
||
containKeysHelper( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as in #86, I'd like to see the branching inline here instead of tucked away in the |
||
this.actual, | ||
keys, | ||
comparator, | ||
false, | ||
'toIncludeKeys', | ||
message || 'Expected %s to include key(s) %s' | ||
) | ||
|
||
return this | ||
} | ||
|
||
toExcludeKeys(keys, comparator, message) { | ||
if (typeof comparator === 'string') { | ||
message = comparator | ||
comparator = null | ||
} | ||
|
||
containKeysHelper( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. |
||
this.actual, | ||
keys, | ||
comparator, | ||
true, | ||
'toExcludeKeys', | ||
message || 'Expected %s to exclude key(s) %s' | ||
) | ||
|
||
return this | ||
} | ||
|
||
toHaveBeenCalled(message) { | ||
const spy = this.actual | ||
|
||
|
@@ -446,7 +483,13 @@ const aliases = { | |
toBeFewerThan: 'toBeLessThan', | ||
toBeMoreThan: 'toBeGreaterThan', | ||
toContain: 'toInclude', | ||
toNotContain: 'toExclude' | ||
toNotContain: 'toExclude', | ||
toIncludeKey: 'toIncludeKeys', | ||
toExcludeKey: 'toExcludeKeys', | ||
toContainKey: 'toIncludeKey', | ||
toNotContainKey: 'toExcludeKey', | ||
toContainKeys: 'toIncludeKeys', | ||
toNotContainKeys: 'toExcludeKeys' | ||
} | ||
|
||
for (const alias in aliases) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import isEqual from 'is-equal' | ||
import isRegExp from 'is-regex' | ||
import has from 'has' | ||
import assert from './assert' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An interesting side effect of making all assertions inline in the |
||
|
||
/** | ||
* Returns true if the given object is a function. | ||
|
@@ -101,3 +103,31 @@ export const objectContains = (object, value, compareValues) => { | |
*/ | ||
export const stringContains = (string, value) => | ||
string.indexOf(value) !== -1 | ||
|
||
/** | ||
* Helper function which abstracts away the core | ||
* functionality from the `toIncludeKeys`/`toExcludeKeys` | ||
* methods. | ||
*/ | ||
export const containKeysHelper = (actual, keys, comparator, exclude, funcName, message) => { | ||
if (!isArray(keys)) | ||
keys = [ keys ] | ||
|
||
if (comparator == null) | ||
comparator = has | ||
|
||
assert( | ||
typeof actual === 'object', | ||
`The "actual" argument in expect(actual).${funcName}() must be an object, not %s`, | ||
typeof actual | ||
) | ||
|
||
const condition = keys.reduce((previous, key) => previous && comparator(actual, key), true) | ||
|
||
assert( | ||
exclude ? !condition : condition, | ||
message, | ||
actual, | ||
keys.join(', ') | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import expect from '../index' | ||
|
||
describe('toExcludeKeys', () => { | ||
it('requires the actual value to have keys', () => { | ||
expect(() => { | ||
expect(1).toExcludeKeys('hello') | ||
}).toThrow(/must be an object/) | ||
}) | ||
|
||
it('throws when there is a key that exists', () => { | ||
expect(() => { | ||
expect({ a: 1 }).toExcludeKeys([ 'a' ]) | ||
}).toThrow(/exclude key/) | ||
}) | ||
|
||
it('does not throw when there is a key that does not exist', () => { | ||
expect(() => { | ||
expect({ a: 1 }).toExcludeKeys([ 'b' ]) | ||
}).toNotThrow() | ||
}) | ||
|
||
it('throws when all keys exist', () => { | ||
expect(() => { | ||
expect({ a: 1, b: 2, c: 3 }).toExcludeKeys([ 'a', 'b', 'c' ]) | ||
}).toThrow(/exclude key/) | ||
}) | ||
|
||
it('does not throw when even one key does not exist', () => { | ||
expect(() => { | ||
expect({ a: 1, c: 3 }).toExcludeKeys([ 'a', 'b', 'c' ]) | ||
}).toNotThrow() | ||
}) | ||
|
||
it('works with arrays', () => { | ||
expect(() => { | ||
expect([ 0, 1, 2 ]).toExcludeKeys([ '0', 1, 2 ]) | ||
}).toThrow(/exclude key/) | ||
|
||
expect(() => { | ||
expect([ 0, 1, 2 ]).toExcludeKeys([ 3 ]) | ||
}).toNotThrow() | ||
}) | ||
|
||
it('allows a single key to be passed', () => { | ||
expect(() => { | ||
expect({ a: 1 }).toExcludeKeys('a') | ||
}).toThrow(/exclude key/) | ||
|
||
expect(() => { | ||
expect({ a: 1 }).toExcludeKeys('b') | ||
}).toNotThrow() | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import expect from '../index' | ||
|
||
describe('toIncludeKeys', () => { | ||
it('requires the actual value to have keys', () => { | ||
expect(() => { | ||
expect(1).toIncludeKeys('hello') | ||
}).toThrow(/must be an object/) | ||
}) | ||
|
||
it('does not throw when there is a key that exists', () => { | ||
expect(() => { | ||
expect({ a: 1 }).toIncludeKeys([ 'a' ]) | ||
}).toNotThrow() | ||
}) | ||
|
||
it('throws when there is a key that does not exist', () => { | ||
expect(() => { | ||
expect({ a: 1 }).toIncludeKeys([ 'b' ]) | ||
}).toThrow(/include key/) | ||
}) | ||
|
||
it('does not throw when all keys exist', () => { | ||
expect(() => { | ||
expect({ a: 1, b: 2, c: 3 }).toIncludeKeys([ 'a', 'b', 'c' ]) | ||
}).toNotThrow() | ||
}) | ||
|
||
it('throws when even one key does not exist', () => { | ||
expect(() => { | ||
expect({ a: 1, c: 3 }).toIncludeKeys([ 'a', 'b', 'c' ]) | ||
}).toThrow(/include key/) | ||
}) | ||
|
||
it('works with arrays', () => { | ||
expect(() => { | ||
expect([ 0, 1, 2 ]).toIncludeKeys([ '0', 1, 2 ]) | ||
}).toNotThrow() | ||
|
||
expect(() => { | ||
expect([ 0, 1, 2 ]).toIncludeKeys([ 3 ]) | ||
}).toThrow(/include key/) | ||
}) | ||
|
||
it('allows a single key to be passed', () => { | ||
expect(() => { | ||
expect({ a: 1 }).toIncludeKeys('a') | ||
}).toNotThrow() | ||
|
||
expect(() => { | ||
expect({ a: 1 }).toIncludeKeys('b') | ||
}).toThrow(/include key/) | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's write this as
toIncludeKey(s)