Skip to content

Commit

Permalink
Improve output of "to have items/values/keys satisfying"
Browse files Browse the repository at this point in the history
  • Loading branch information
sunesimonsen committed Jun 12, 2015
1 parent b392012 commit 8b4d12f
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 167 deletions.
8 changes: 6 additions & 2 deletions documentation/api/promise-all.md
Expand Up @@ -60,6 +60,10 @@ return expect.promise.all({
```

```output
failed expectation in { a: '0', b: 1 }:
a: expected '0' to be a number after a short delay
expected { a: '0', b: 1 } to have values satisfying 'to be a number after a short delay'
{
a: '0', // expected '0' to be a number after a short delay
b: 1
}
```
17 changes: 13 additions & 4 deletions documentation/api/promise-any.md
Expand Up @@ -79,8 +79,17 @@ return expect.promise.any({
```output
aggregate error
0: expected '42' to be a number after a short delay
1: failed expectation in [ 0, '1', 2 ]:
1: expected '1' to be a number after a short delay
2: failed expectation in { a: '0', b: 1 }:
a: expected '0' to be a number after a short delay
1: expected [ 0, '1', 2 ] to have values satisfying expect.it('to be a number after a short delay')
[
0,
'1', // expected '1' to be a number after a short delay
2
]
2: expected { a: '0', b: 1 } to have values satisfying 'to be a number after a short delay'
{
a: '0', // expected '0' to be a number after a short delay
b: 1
}
```
8 changes: 6 additions & 2 deletions documentation/api/promise-settle.md
Expand Up @@ -63,7 +63,11 @@ return expect.promise.all(promises).caught(function () {
{
foo: ⨯ expected '42' to be a number after a short delay
bar: ✓
baz: ⨯ failed expectation in { a: '1', b: 2 }:
a: expected '1' to be a number after a short delay
baz: ⨯ expected { a: '1', b: 2 } to have values satisfying 'to be a number after a short delay'
{
a: '1', // expected '1' to be a number after a short delay
b: 2
}
}
```
37 changes: 28 additions & 9 deletions documentation/assertions/array-like/to-have-items-satisfying.md
Expand Up @@ -28,12 +28,22 @@ expect([ [0, 1, 2], [4, '5', '6'], [7, '8', 9] ],
```

```output
failed expectation in [ [ 0, 1, 2 ], [ 4, '5', '6' ], [ 7, '8', 9 ] ]:
1: failed expectation in [ 4, '5', '6' ]:
1: expected '5' to be a number
2: expected '6' to be a number
2: failed expectation in [ 7, '8', 9 ]:
1: expected '8' to be a number
expected [ [ 0, 1, 2 ], [ 4, '5', '6' ], [ 7, '8', 9 ] ]
to have values satisfying 'to have items satisfying', 'to be a number'
[
[...],
[
4,
'5', // expected '5' to be a number
'6' // expected '6' to be a number
],
[
7,
'8', // expected '8' to be a number
9
]
]
```

Here a another example:
Expand All @@ -44,7 +54,16 @@ expect([0, 1, 2, 3, 4], 'to have items satisfying',
```

```output
failed expectation in [ 0, 1, 2, 3, 4 ]:
0: ✓ expected 0 to be a number and
⨯ expected 0 to be positive
expected [ 0, 1, 2, 3, 4 ] to have values satisfying
expect.it('to be a number')
.and('to be positive')
[
0, // ✓ expected 0 to be a number and
// ⨯ expected 0 to be positive
1,
2,
3,
4
]
```
11 changes: 9 additions & 2 deletions documentation/assertions/object/to-have-keys-satisfying.md
Expand Up @@ -25,6 +25,13 @@ expect({ foo: 0, bar: 1, baz: 2, qux: 3, quux: 4 },
```

```output
failed expectation on keys foo, bar, baz, qux, quux:
quux: expected 'quux' to match /^[a-z]{3}$/
expected { foo: 0, bar: 1, baz: 2, qux: 3, quux: 4 } to have keys satisfying 'to match', /^[a-z]{3}$/
{
foo: 0,
bar: 1,
baz: 2,
qux: 3,
quux: 4 // expected 'quux' to match /^[a-z]{3}$/
}
```
21 changes: 15 additions & 6 deletions documentation/assertions/object/to-have-values-satisfying.md
Expand Up @@ -26,10 +26,19 @@ expect({ foo: [0, 1, 2], bar: [4, 5, 6], baz: [7, 8, 9] },
```

```output
failed expectation in { foo: [ 0, 1, 2 ], bar: [ 4, 5, 6 ], baz: [ 7, 8, 9 ] }:
baz: failed expectation in [ 7, 8, 9 ]:
1: ✓ expected 8 to be a number and
⨯ expected 8 to be below 8
2: ✓ expected 9 to be a number and
⨯ expected 9 to be below 8
expected { foo: [ 0, 1, 2 ], bar: [ 4, 5, 6 ], baz: [ 7, 8, 9 ] } to have values satisfying
'to have items satisfying', expect.it('to be a number')
.and('to be below', 8)
{
foo: [...],
bar: [...],
baz: [
7,
8, // ✓ expected 8 to be a number and
// ⨯ expected 8 to be below 8
9 // ✓ expected 9 to be a number and
// ⨯ expected 9 to be below 8
]
}
```
129 changes: 59 additions & 70 deletions lib/assertions.js
Expand Up @@ -434,6 +434,7 @@ module.exports = function (expect) {
'to have values satisfying',
'to be (a map|a hash|an object) whose values satisfy'
], function (expect, subject) {
var that = this;
var extraArgs = Array.prototype.slice.call(arguments, 2);
if (extraArgs.length === 0) {
throw new Error('Assertion "' + this.testDescription + '" expects a third argument');
Expand All @@ -442,45 +443,35 @@ module.exports = function (expect) {
expect(subject, 'not to equal', {});
this.errorMode = 'bubble';

var promiseByKey = {};
expect.findTypeOf(subject).getKeys(subject).forEach(function (key, index) {
promiseByKey[key] = expect.promise(function () {
if (typeof extraArgs[0] === 'function') {
return extraArgs[0](subject[key], index);
} else {
return expect.apply(expect, [subject[key], 'to satisfy assertion'].concat(extraArgs));
}
var subjectType = expect.findTypeOf(subject);
var keys = subjectType.getKeys(subject);
var expected = Array.isArray(subject) ? [] : {};
if (typeof extraArgs[0] === 'function') {
keys.forEach(function (key, index) {
expected[key] = function (s) {
return extraArgs[0](s, index);
};
});
});
} else {
keys.forEach(function (key, index) {
expected[key] = function (s) {
return expect.apply(expect, [s, 'to satisfy assertion'].concat(extraArgs));
};
});
}

return expect.promise.all(promiseByKey).caught(function () {
return expect.promise.settle(promiseByKey).then(function () {
expect.fail(function (output) {
var subjectOutput = expect.inspect(subject);
output.error('failed expectation in');
if (subjectOutput.size().height > 1) {
output.nl();
} else {
output.sp();
}
subjectOutput.error(':');
output.block(subjectOutput).nl();
output.indentLines();

var seenFirstRejected = false;
Object.keys(promiseByKey).forEach(function (key) {
var promise = promiseByKey[key];
if (promise.isRejected()) {
var error = promise.reason();
if (seenFirstRejected) {
output.nl();
} else {
seenFirstRejected = true;
}
output.i().text(key).text(': ').block(error.getErrorMessage());
}
});
});
return expect.withError(function () {
return expect(subject, 'to satisfy', expected);
}, function (err) {
expect.fail({
message: function (output) {
output.append(that.standardErrorMessage({ compact: true }));
},
diff: function () {
var diff = err.getDiff();
diff.inline = true;
return diff;
}
});
});
});
Expand All @@ -503,6 +494,7 @@ module.exports = function (expect) {
'to have keys satisfying',
'to be (a map|a hash|an object) whose (keys|properties) satisfy'
], function (expect, subject) {
var that = this;
var extraArgs = Array.prototype.slice.call(arguments, 2);
if (extraArgs.length === 0) {
throw new Error('Assertion "' + this.testDescription + '" expects a third argument');
Expand All @@ -512,40 +504,35 @@ module.exports = function (expect) {
expect(subject, 'not to equal', {});
this.errorMode = 'bubble';

var subjectKeys = expect.findTypeOf(subject).getKeys(subject),
promiseByKey = {};
subjectKeys.forEach(function (key) {
promiseByKey[key] = expect.promise(function () {
if (typeof extraArgs[0] === 'function') {
var subjectType = expect.findTypeOf(subject);
var keys = subjectType.getKeys(subject);
var expected = Array.isArray(subject) ? [] : {};
if (typeof extraArgs[0] === 'function') {
keys.forEach(function (key, index) {
expected[key] = function () {
return extraArgs[0](key, subject[key]);
} else {
};
});
} else {
keys.forEach(function (key, index) {
expected[key] = function () {
return expect.apply(expect, [key, 'to satisfy assertion'].concat(extraArgs));
}
};
});
}, this);

return expect.promise.all(promiseByKey).caught(function () {
return expect.promise.settle(promiseByKey).then(function () {
expect.fail(function (output) {
output.error('failed expectation on keys ')
.text(subjectKeys.join(', '))
.error(':').nl()
.indentLines();

var seenFirstRejected = false;
Object.keys(promiseByKey).forEach(function (key) {
var promise = promiseByKey[key];
if (promise.isRejected()) {
var error = promise.reason();
if (seenFirstRejected) {
output.nl();
} else {
seenFirstRejected = true;
}
output.i().text(key).text(': ').block(error.getErrorMessage());
}
});
});
}

return expect.withError(function () {
return expect(subject, 'to satisfy', expected);
}, function (err) {
expect.fail({
message: function (output) {
output.append(that.standardErrorMessage({ compact: true }));
},
diff: function () {
var diff = err.getDiff();
diff.inline = true;
return diff;
}
});
});
});
Expand Down Expand Up @@ -677,7 +664,7 @@ module.exports = function (expect) {
return value(subject);
}, function (e) {
expect.fail({
diff: function (output, diff, inspect, equal) {
diff: function (output) {
return {
diff: output.append(e.getErrorMessage()),
inline: false
Expand Down Expand Up @@ -770,7 +757,9 @@ module.exports = function (expect) {
} else if (conflicting || arrayItemOutOfRange) {
var keyDiff = conflicting && conflicting.getDiff();
isInlineDiff = !keyDiff || keyDiff.inline ;
if (typeof value[key] === 'function') {
if (keyDiff && keyDiff.diff && keyDiff.inline) {
valueOutput = keyDiff.diff;
} else if (typeof value[key] === 'function') {
isInlineDiff = false;
annotation.append(conflicting.getErrorMessage());
} else if (!keyDiff || (keyDiff && !keyDiff.inline)) {
Expand Down

0 comments on commit 8b4d12f

Please sign in to comment.