/
TestUtils.js
123 lines (102 loc) · 3.3 KB
/
TestUtils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import isRegExp from 'is-regex'
import whyNotStrictlyEqual from 'is-equal/why'
import objectKeys from 'object-keys'
/**
* Returns the reason why the given arguments are not *conceptually*
* equal, if any; the empty string otherwise.
*/
export const whyNotEqual = (a, b) =>
(a == b ? '' : whyNotStrictlyEqual(a, b)) // eslint-disable-line eqeqeq
/**
* Returns true if the given arguments are *conceptually* equal.
*/
export const isEqual = (a, b) =>
whyNotEqual(a, b) === ''
/**
* Returns true if the given object is a function.
*/
export const isFunction = (object) =>
typeof object === 'function'
/**
* Returns true if the given object is an array.
*/
export const isArray = (object) =>
Array.isArray(object)
/**
* Returns true if the given object is an object.
*/
export const isObject = (object) =>
object && !isArray(object) && typeof object === 'object'
/**
* Returns true if the given object is an instanceof value
* or its typeof is the given value.
*/
export const isA = (object, value) => {
if (isFunction(value))
return object instanceof value
if (value === 'array')
return Array.isArray(object)
return typeof object === value
}
/**
* Returns true if the given function throws the given value
* when invoked. The value may be:
*
* - undefined, to merely assert there was a throw
* - a constructor function, for comparing using instanceof
* - a regular expression, to compare with the error message
* - a string, to find in the error message
*/
export const functionThrows = (fn, context, args, value) => {
try {
fn.apply(context, args)
} catch (error) {
if (value == null)
return true
if (isFunction(value) && error instanceof value)
return true
const message = error.message || error
if (typeof message === 'string') {
if (isRegExp(value) && value.test(error.message))
return true
if (typeof value === 'string' && message.indexOf(value) !== -1)
return true
}
}
return 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 arrayContains = (array, value, compareValues) =>
array.some(item => compareValues(item, value) !== false)
const ownEnumerableKeys = (object) => {
if (typeof Reflect === 'object' && typeof Reflect.ownKeys === 'function') {
return Reflect.ownKeys(object)
.filter(key => Object.getOwnPropertyDescriptor(object, key).enumerable)
}
if (typeof Object.getOwnPropertySymbols === 'function') {
return Object.getOwnPropertySymbols(object)
.filter(key => Object.getOwnPropertyDescriptor(object, key).enumerable)
.concat(objectKeys(object))
}
return objectKeys(object)
}
/**
* Returns true if the given object contains the value, false
* otherwise. The compareValues function must return false to
* indicate a non-match.
*/
export const objectContains = (object, value, compareValues) =>
ownEnumerableKeys(value).every(k => {
if (isObject(object[k]) && isObject(value[k]))
return objectContains(object[k], value[k], compareValues)
return compareValues(object[k], value[k])
})
/**
* Returns true if the given string contains the value, false otherwise.
*/
export const stringContains = (string, value) =>
string.indexOf(value) !== -1