mirror of https://github.com/lukechilds/ow.git
Sam Verschueren
7 years ago
committed by
Sindre Sorhus
4 changed files with 182 additions and 1 deletions
@ -0,0 +1,113 @@ |
|||
import is from '@sindresorhus/is'; |
|||
import isEqual = require('lodash.isequal'); // tslint:disable-line:no-require-imports
|
|||
import {Predicate, Context} from './predicate'; |
|||
import hasItems from '../utils/has-items'; |
|||
import ofType from '../utils/of-type'; |
|||
|
|||
export class ObjectPredicate extends Predicate<object> { |
|||
constructor(context?: Context) { |
|||
super('object', context); |
|||
} |
|||
|
|||
/** |
|||
* Test if an Object is a plain object. |
|||
*/ |
|||
get plain() { |
|||
return this.addValidator({ |
|||
message: () => 'Expected object to be a plain object', |
|||
validator: object => is.plainObject(object) |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Test an object to be empty. |
|||
*/ |
|||
get empty() { |
|||
return this.addValidator({ |
|||
message: object => `Expected object to be empty, got \`${JSON.stringify(object)}\``, |
|||
validator: object => Object.keys(object).length === 0 |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Test an object to be not empty. |
|||
*/ |
|||
get nonEmpty() { |
|||
return this.addValidator({ |
|||
message: () => 'Expected object to not be empty', |
|||
validator: object => Object.keys(object).length > 0 |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Test all the values in the object to match the provided predicate. |
|||
* |
|||
* @param predicate The predicate that should be applied against every value in the object. |
|||
*/ |
|||
valuesOfType<T>(predicate: Predicate<T>) { |
|||
return this.addValidator({ |
|||
message: (_, error) => error, |
|||
validator: (object: any) => { |
|||
const values = Object.keys(object).map(key => object[key]); |
|||
|
|||
return ofType(values, predicate); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Test an object to be deeply equal to the provided object. |
|||
* |
|||
* @param expected Expected object to match. |
|||
*/ |
|||
deepEqual(expected: object) { |
|||
return this.addValidator({ |
|||
message: object => `Expected object to be deeply equal to \`${JSON.stringify(expected)}\`, got \`${JSON.stringify(object)}\``, |
|||
validator: object => isEqual(object, expected) |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Test an object to be of a specific instance type. |
|||
* |
|||
* @param instance The expected instance type of the object. |
|||
*/ |
|||
instanceOf(instance: any) { |
|||
return this.addValidator({ |
|||
message: (object: any) => { |
|||
let name = object.constructor.name; |
|||
|
|||
if (!name || name === 'Object') { |
|||
name = JSON.stringify(object); |
|||
} |
|||
|
|||
return `Expected \`${name}\` to be of type \`${instance.name}\``; |
|||
}, |
|||
validator: object => object instanceof instance |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Test an object to include all the provided keys. |
|||
* |
|||
* @param keys The keys that should be present in the object. |
|||
*/ |
|||
hasKeys(...keys: string[]) { |
|||
return this.addValidator({ |
|||
message: (_, missingKeys) => `Expected object to have keys \`${JSON.stringify(missingKeys)}\``, |
|||
validator: object => hasItems(new Set(Object.keys(object)), keys) |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Test an object to include any of the provided keys. |
|||
* |
|||
* @param keys The keys that could be a key in the object. |
|||
*/ |
|||
hasAnyKeys(...keys: string[]) { |
|||
return this.addValidator({ |
|||
message: () => `Expected object to have any key of \`${JSON.stringify(keys)}\``, |
|||
validator: (object: any) => keys.some(key => object[key] !== undefined) |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,60 @@ |
|||
import test from 'ava'; |
|||
import m from '..'; |
|||
|
|||
class Unicorn {} // tslint:disable-line
|
|||
|
|||
test('object', t => { |
|||
t.notThrows(() => m({}, m.object)); |
|||
t.notThrows(() => m(new Error('foo'), m.object)); |
|||
t.throws(() => m('foo' as any, m.object), 'Expected argument to be of type `object` but received type `string`'); |
|||
t.throws(() => m(1 as any, m.object), 'Expected argument to be of type `object` but received type `number`'); |
|||
}); |
|||
|
|||
test('object.plain', t => { |
|||
t.notThrows(() => m({}, m.object.plain)); |
|||
t.throws(() => m(new Error('foo'), m.object.plain), 'Expected object to be a plain object'); |
|||
}); |
|||
|
|||
test('object.empty', t => { |
|||
t.notThrows(() => m({}, m.object.empty)); |
|||
t.throws(() => m({unicorn: '🦄'}, m.object.empty), 'Expected object to be empty, got `{"unicorn":"🦄"}`'); |
|||
}); |
|||
|
|||
test('object.nonEmpty', t => { |
|||
t.notThrows(() => m({unicorn: '🦄'}, m.object.nonEmpty)); |
|||
t.throws(() => m({}, m.object.nonEmpty), 'Expected object to not be empty'); |
|||
}); |
|||
|
|||
test('object.valuesOfType', t => { |
|||
t.notThrows(() => m({unicorn: '🦄'}, m.object.valuesOfType(m.string))); |
|||
t.notThrows(() => m({unicorn: '🦄', rainbow: '🌈'}, m.object.valuesOfType(m.string))); |
|||
t.notThrows(() => m({unicorn: 1, rainbow: 2}, m.object.valuesOfType(m.number))); |
|||
t.throws(() => m({unicorn: '🦄', rainbow: 2}, m.object.valuesOfType(m.string)), 'Expected argument to be of type `string` but received type `number`'); |
|||
t.throws(() => m({unicorn: 'a', rainbow: 'b'}, m.object.valuesOfType(m.string.minLength(2))), 'Expected string to have a minimum length of `2`, got `a`'); |
|||
}); |
|||
|
|||
test('object.deepEqual', t => { |
|||
t.notThrows(() => m({unicorn: '🦄'}, m.object.deepEqual({unicorn: '🦄'}))); |
|||
t.notThrows(() => m({unicorn: '🦄', rain: {bow: '🌈'}}, m.object.deepEqual({unicorn: '🦄', rain: {bow: '🌈'}}))); |
|||
t.throws(() => m({unicorn: '🦄'}, m.object.deepEqual({rainbow: '🌈'})), 'Expected object to be deeply equal to `{"rainbow":"🌈"}`, got `{"unicorn":"🦄"}`'); |
|||
}); |
|||
|
|||
test('object.instanceOf', t => { |
|||
t.notThrows(() => m(new Error('🦄'), m.object.instanceOf(Error))); |
|||
t.notThrows(() => m(new Unicorn(), m.object.instanceOf(Unicorn))); |
|||
t.throws(() => m(new Unicorn(), m.object.instanceOf(Error)), 'Expected `Unicorn` to be of type `Error`'); |
|||
t.throws(() => m(new Error('🦄'), m.object.instanceOf(Unicorn)), 'Expected `Error` to be of type `Unicorn`'); |
|||
t.throws(() => m({unicorn: '🦄'}, m.object.instanceOf(Unicorn)), 'Expected `{"unicorn":"🦄"}` to be of type `Unicorn`'); |
|||
}); |
|||
|
|||
test('object.hasKeys', t => { |
|||
t.notThrows(() => m({unicorn: '🦄'}, m.object.hasKeys('unicorn'))); |
|||
t.notThrows(() => m({unicorn: '🦄', rainbow: '🌈'}, m.object.hasKeys('unicorn', 'rainbow'))); |
|||
t.throws(() => m({unicorn: '🦄'}, m.object.hasKeys('unicorn', 'rainbow')), 'Expected object to have keys `["rainbow"]`'); |
|||
}); |
|||
|
|||
test('object.hasAnyKeys', t => { |
|||
t.notThrows(() => m({unicorn: '🦄'}, m.object.hasAnyKeys('unicorn', 'rainbow'))); |
|||
t.notThrows(() => m({unicorn: '🦄', rainbow: '🌈'}, m.object.hasAnyKeys('unicorn'))); |
|||
t.throws(() => m({unicorn: '🦄'}, m.object.hasAnyKeys('foo')), 'Expected object to have any key of `["foo"]`'); |
|||
}); |
Loading…
Reference in new issue