Skip to content

Commit

Permalink
Merge a9d9403 into 4c5ea7c
Browse files Browse the repository at this point in the history
  • Loading branch information
papandreou committed May 26, 2018
2 parents 4c5ea7c + a9d9403 commit 2b7c976
Show file tree
Hide file tree
Showing 90 changed files with 1,187 additions and 824 deletions.
79 changes: 50 additions & 29 deletions documentation/api/UnexpectedError.md
Expand Up @@ -25,25 +25,30 @@ output.appendErrorMessage(error);
This is useful if you want to combine multiple errors in one assertion:

```js
expect.addAssertion("<array> to have item satisfying <any+>", function (expect, subject) {
expect.addAssertion('<array> to have item satisfying <any+>', function(
expect,
subject
) {
var args = Array.prototype.slice.call(arguments, 2);
var promises = subject.map(function (item) {
return expect.promise(function () {
var promises = subject.map(function(item) {
return expect.promise(function() {
return expect.apply(expect, [item].concat(args));
});
});

return expect.promise.settle(promises).then(function () {
var failed = promises.every(function (promise) {
return expect.promise.settle(promises).then(function() {
var failed = promises.every(function(promise) {
return promise.isRejected();
});

if (failed) {
expect.fail({
diff: function (output, diff, inspect, equal) {
diff: function(output, diff, inspect, equal) {
output.inline = true;
promises.forEach(function (promise, index) {
if (index > 0) { output.nl(2); }
promises.forEach(function(promise, index) {
if (index > 0) {
output.nl(2);
}
var error = promise.reason();
// the error is connected to the current scope
// but we are just interested in the nested error
Expand Down Expand Up @@ -92,16 +97,23 @@ We could for example change the error mode for all the errors in the
chain to `nested`:

```js
expect.addAssertion('<any> detailed to be <any>', function (expect, subject, value) {
expect.addAssertion('<any> detailed to be <any>', function(
expect,
subject,
value
) {
expect.errorMode = 'bubble';
expect.withError(function () {
expect(subject, 'to be', value);
}, function (err) {
err.getParents().forEach(function (e) {
e.errorMode = 'nested';
});
expect.fail(err);
});
expect.withError(
function() {
expect(subject, 'to be', value);
},
function(err) {
err.getParents().forEach(function(e) {
e.errorMode = 'nested';
});
expect.fail(err);
}
);
});

expect('f00!', 'detailed to be', 'foo!');
Expand Down Expand Up @@ -145,18 +157,27 @@ create the diff. Now you can delegate to that method from
`expect.fail`:

```js
expect.addAssertion('<any> to be completely custom', function (expect, subject) {
return expect.withError(function () {
expect(subject, 'to satisfy', { custom: true });
}, function (err) {
var createDiff = err.getDiffMethod();
expect.fail({
diff: function (output, diff, inspect, equal) {
output.text('~~~~~~~~~~~~~~').sp().success('custom').sp().text('~~~~~~~~~~~~~~').nl();
return createDiff(output, diff, inspect, equal);
}
});
});
expect.addAssertion('<any> to be completely custom', function(expect, subject) {
return expect.withError(
function() {
expect(subject, 'to satisfy', { custom: true });
},
function(err) {
var createDiff = err.getDiffMethod();
expect.fail({
diff: function(output, diff, inspect, equal) {
output
.text('~~~~~~~~~~~~~~')
.sp()
.success('custom')
.sp()
.text('~~~~~~~~~~~~~~')
.nl();
return createDiff(output, diff, inspect, equal);
}
});
}
);
});

expect({ custom: false }, 'to be completely custom');
Expand Down
109 changes: 69 additions & 40 deletions documentation/api/addAssertion.md
Expand Up @@ -11,20 +11,25 @@ New assertions can be added to Unexpected the following way.

```js
var errorMode = 'default'; // use to control the error mode later in the example
expect.addAssertion('<array> [not] to be (sorted|ordered) <function?>', function (expect, subject, cmp) {
expect.errorMode = errorMode;
expect(subject, '[not] to equal', [].concat(subject).sort(cmp));
});
expect.addAssertion(
'<array> [not] to be (sorted|ordered) <function?>',
function(expect, subject, cmp) {
expect.errorMode = errorMode;
expect(subject, '[not] to equal', [].concat(subject).sort(cmp));
}
);
```

The above assertion definition makes the following expects possible:

```js
expect([1,2,3], 'to be sorted');
expect([1,2,3], 'to be ordered');
expect([2,1,3], 'not to be sorted');
expect([2,1,3], 'not to be ordered');
expect([3,2,1], 'to be sorted', function (x, y) { return y - x; });
expect([1, 2, 3], 'to be sorted');
expect([1, 2, 3], 'to be ordered');
expect([2, 1, 3], 'not to be sorted');
expect([2, 1, 3], 'not to be ordered');
expect([3, 2, 1], 'to be sorted', function(x, y) {
return y - x;
});
```

Let's dissect the different parts of the custom assertion we just
Expand Down Expand Up @@ -88,14 +93,25 @@ an output function on the assertion.
Here is a few examples:

```js
expect.addAssertion('<number> to be contained by <number> <number>', function (expect, subject, start, finish) {
expect.subjectOutput = function (output) {
output.text('point ').jsNumber(subject);
};
expect.argsOutput = function (output) {
output.text('interval ').text('[').appendInspected(start).text(';').appendInspected(finish).text(']');
};
expect(subject >= start && subject <= finish, '[not] to be truthy');
expect.addAssertion('<number> to be contained by <number> <number>', function(
expect,
subject,
start,
finish
) {
expect.subjectOutput = function(output) {
output.text('point ').jsNumber(subject);
};
expect.argsOutput = function(output) {
output
.text('interval ')
.text('[')
.appendInspected(start)
.text(';')
.appendInspected(finish)
.text(']');
};
expect(subject >= start && subject <= finish, '[not] to be truthy');
});

expect(4, 'to be contained by', 8, 10);
Expand All @@ -106,14 +122,22 @@ expected point 4 to be contained by interval [8;10]
```

```js
expect.addAssertion('<number> to be similar to <number> <number?>', function (expect, subject, value, epsilon) {
if (typeof epsilon !== 'number') {
epsilon = 1e-9;
}
expect.argsOutput[2] = function (output) {
output.text('(epsilon: ').jsNumber(epsilon.toExponential()).text(')')
}
expect(Math.abs(subject - value), 'to be less than or equal to', epsilon);
expect.addAssertion('<number> to be similar to <number> <number?>', function(
expect,
subject,
value,
epsilon
) {
if (typeof epsilon !== 'number') {
epsilon = 1e-9;
}
expect.argsOutput[2] = function(output) {
output
.text('(epsilon: ')
.jsNumber(epsilon.toExponential())
.text(')');
};
expect(Math.abs(subject - value), 'to be less than or equal to', epsilon);
});

expect(4, 'to be similar to', 4.0001);
Expand All @@ -130,7 +154,7 @@ message for the custom assertion will be used. In the case of our
_sorted_ assertion fails, the output will be:

```js
expect([ 1, 3, 2, 4 ], 'to be sorted');
expect([1, 3, 2, 4], 'to be sorted');
```

```output
Expand All @@ -154,7 +178,7 @@ If we change the error mode to _bubble_, we get the following output:

```js
errorMode = 'bubble';
expect([ 1, 3, 2, 4 ], 'to be sorted');
expect([1, 3, 2, 4], 'to be sorted');
```

```output
Expand All @@ -176,7 +200,7 @@ If we change the error mode to _nested_, we get the following output:

```js
errorMode = 'nested';
expect([ 1, 3, 2, 4 ], 'to be sorted');
expect([1, 3, 2, 4], 'to be sorted');
```

```output
Expand All @@ -199,7 +223,7 @@ If we change the error mode to _defaultOrNested_, we get the following output:

```js
errorMode = 'defaultOrNested';
expect([ 1, 3, 2, 4 ], 'to be sorted');
expect([1, 3, 2, 4], 'to be sorted');
```

```output
Expand All @@ -221,7 +245,7 @@ If we change the error mode to _diff_, we get the following output:

```js
errorMode = 'diff';
expect([ 1, 3, 2, 4 ], 'to be sorted');
expect([1, 3, 2, 4], 'to be sorted');
```

```output
Expand All @@ -234,7 +258,6 @@ expect([ 1, 3, 2, 4 ], 'to be sorted');
]
```


### Asynchronous assertions

Unexpected comes with built-in support for asynchronous
Expand All @@ -250,9 +273,9 @@ function Timelock(value, delay) {
this.delay = delay;
}

Timelock.prototype.getValue = function (cb) {
Timelock.prototype.getValue = function(cb) {
var that = this;
setTimeout(function () {
setTimeout(function() {
cb(that.value);
}, this.delay);
};
Expand All @@ -272,21 +295,27 @@ First we need to define a [type](../addType/) for handling the `Timelock`:
```js
expect.addType({
name: 'Timelock',
identify: function (value) {
identify: function(value) {
return value && value instanceof Timelock;
},
inspect: function (value, depth, output) {
inspect: function(value, depth, output) {
output.jsFunctionName('Timelock');
}
});
```

```js
expect.addAssertion('<Timelock> to satisfy <any>', function (expect, subject, spec) {
return expect.promise(function (run) {
subject.getValue(run(function (value) {
return expect(value, 'to satisfy', spec);
}));
expect.addAssertion('<Timelock> to satisfy <any>', function(
expect,
subject,
spec
) {
return expect.promise(function(run) {
subject.getValue(
run(function(value) {
return expect(value, 'to satisfy', spec);
})
);
});
});
```
Expand Down
36 changes: 36 additions & 0 deletions documentation/api/addStyle.md
@@ -0,0 +1,36 @@
# expect.addStyle(...)

Install a single [MagicPen](https://github.com/sunesimonsen/magicpen) style into the
`expect` instance, so that it's used when rendering error messages and diffs.

Proxies through to [magicPen.addStyle](https://github.com/sunesimonsen/magicpen#addstylestyle-handler).
See the documentation there.

Example:

```js
expect.addStyle('jsString', function(text, rainbowColors) {
rainbowColors = rainbowColors || [
'gray',
'red',
'green',
'yellow',
'blue',
'magenta',
'cyan'
];
for (var i = 0; i < text.length; i += 1) {
var color = rainbowColors[i % rainbowColors.length];
this.text(text[i], color);
}
});

expect('foobar', 'to equal', 'foo bar');
```

```output
expected 'foobar' to equal 'foo bar'
-foobar
+foo bar
```

0 comments on commit 2b7c976

Please sign in to comment.