-
Notifications
You must be signed in to change notification settings - Fork 0
/
chai-somewhere.js
98 lines (85 loc) · 3.79 KB
/
chai-somewhere.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
var traverse = require('traverse');
module.exports = function (chai, utils) {
utils.addProperty(chai.Assertion.prototype, 'somewhere', setSomewhereFlag);
utils.addProperty(chai.Assertion.prototype, 'anywhere', setSomewhereFlag);
utils.overwriteChainableMethod(chai.Assertion.prototype, 'contain', overwriteWithTypeFilter(isArrayOrString), keepSameBehaviour);
utils.overwriteChainableMethod(chai.Assertion.prototype, 'contains', overwriteWithTypeFilter(isArrayOrString), keepSameBehaviour);
utils.overwriteChainableMethod(chai.Assertion.prototype, 'include', overwriteWithTypeFilter(isArrayOrString), keepSameBehaviour);
utils.overwriteChainableMethod(chai.Assertion.prototype, 'includes', overwriteWithTypeFilter(isArrayOrString), keepSameBehaviour);
utils.overwriteMethod(chai.Assertion.prototype, 'property', overwriteWithTypeFilter(isArrayOrObject));
function setSomewhereFlag() {
utils.flag(this, 'somewhere', true);
return this;
}
function isArrayOrObject(object) {
return Array.isArray(object) || typeof object === 'object';
}
function isArrayOrString(object) {
return Array.isArray(object) || object instanceof Array || typeof object === 'string';
}
function keepSameBehaviour(_super) {
return _super;
}
function overwriteWithTypeFilter(typeFilter) {
return function (_super) {
return function () {
if (utils.flag(this, 'somewhere')) {
performSomewhereAssertion(this, _super, arguments, typeFilter);
} else {
_super.apply(this, arguments);
}
};
};
}
function performSomewhereAssertion(assertion, overwrittenMethod, testArguments, typeFilter) {
var object = utils.flag(assertion, 'object');
if (utils.flag(assertion, 'negate')) {
checkAssertionNegativeCase(assertion, object, overwrittenMethod, testArguments, typeFilter);
} else {
checkAssertionPositiveCase(assertion, object, overwrittenMethod, testArguments, typeFilter);
}
}
function checkAssertionNegativeCase(assertion, object, overwrittenMethod, testArguments, typeFilter) {
traverse(object).forEach(function (node) {
utils.flag(assertion, 'object', node);
if (!typeFilter || typeFilter(node)) {
silencePropertyCheck(function () {
overwrittenMethod.apply(assertion, testArguments)
});
}
});
}
// When a key and value are passed to the .property assertion, chai check that the object
// tested has the provided key. We do not want this check as we don't expect all objects in the
// graph to contain the key.
function silencePropertyCheck(assertion) {
try {
assertion();
} catch (error) {
if (error.message.indexOf('has no property') === -1) {
throw error;
}
}
}
function checkAssertionPositiveCase(assertion, object, overwrittenMethod, testArguments, typeFilter) {
var found = false;
traverse(object).forEach(function (node) {
if (!found) {
if (!typeFilter || typeFilter(node)) {
try {
utils.flag(assertion, 'object', node);
overwrittenMethod.apply(assertion, testArguments);
found = true;
} catch (ignore) {
// Keep looking.
}
}
}
});
if (!found) {
// Call again with root object to get best error message.
utils.flag(assertion, 'object', object);
overwrittenMethod.apply(assertion, testArguments);
}
}
};