Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alter the plugin to use stricter "to satisfy" semantics. #37

Merged
merged 10 commits into from Aug 8, 2020
55 changes: 55 additions & 0 deletions documentation/assertions/Set/to-have-items-satisfying.md
@@ -0,0 +1,55 @@
Asserts the items contained by a Set satisfy a particular list of items.

```js
expect(new Set([1, 2, 3]), 'to have items satisfying', [1, { foo: 'bar' }, 3]);
alexjeffburke marked this conversation as resolved.
Show resolved Hide resolved
```

```output
expected Set([ 1, 2, 3 ]) to have items satisfying [ 1, { foo: 'bar' }, 3 ]

Set([
1, // should equal [ 1, { foo: 'bar' }, 3 ]
2, // should equal [ 1, { foo: 'bar' }, 3 ]
3 // should equal [ 1, { foo: 'bar' }, 3 ]
])
```

In order to check a property holds for all the items, an assertion can be
passed as the argument – in this example we assert that all the items in
the set are numbers:

```js
expect(new Set([1, 2, []]), 'to have items satisfying', 'to be a number');
```

```output
expected Set([ 1, 2, [] ]) to have items satisfying to be a number

Set([
1,
2,
[] // should be a number
])
```

The exact number of elements in a Set must always be matched. However, nested
objects are, be default, compared using "satisfy" semantics which allow missing
properties. In order to enforce that all properties are present, the `exhaustively`
flag can be used:

```js
expect(new Set([[{ foo: true, bar: true }], [1]]), 'to have items satisfying', [
expect.it('to be an object'),
]);
```

```output
expected Set to have items satisfying [ expect.it('to be an object') ]

Set([
[ { foo: true, bar: true } ],
[
1 // should be an object
]
])
```
42 changes: 27 additions & 15 deletions documentation/assertions/Set/to-satisfy.md
Expand Up @@ -2,41 +2,53 @@ Asserts that a Set instance has at least one element satisfying each given
spec.

```js
expect(new Set([1, 2, 3]), 'to satisfy', [
1,
expect.it('to be less than or equal to', 1),
expect.it('to be greater than', 10),
]);
expect(
new Set([1, 2, 3]),
'to satisfy',
new Set([
1,
expect.it('to be less than or equal to', 1),
expect.it('to be greater than', 10),
])
);
```

```output
expected Set([ 1, 2, 3 ]) to satisfy
[
Set([
1,
expect.it('to be less than or equal to', 1),
expect.it('to be greater than', 10)
]
])

Set([
1,
2,
3
2, // should be removed
3 // should be removed
// missing: should be greater than 10
])
```

If the subject should not contain additional elements, use the `exhaustively`
flag:
The exact number of elements in a Set must always be matched. However, nested
objects are, be default, compared using "satisfy" semantics which allow missing
properties. In order to enforce that all properties are present, the `exhaustively`
flag can be used:

```js
expect(new Set([1, 2]), 'to exhaustively satisfy', [2]);
expect(
new Set([1, { foo: true, bar: false }]),
'to exhaustively satisfy',
new Set([1, { foo: true }])
);
```

```output
expected Set([ 1, 2 ]) to exhaustively satisfy [ 2 ]
expected Set([ 1, { foo: true, bar: false } ])
to exhaustively satisfy Set([ 1, { foo: true } ])

Set([
1, // should be removed
2
1,
{ foo: true, bar: false } // should be removed
// missing { foo: true }
])
```
8 changes: 4 additions & 4 deletions documentation/assertions/array-like/with-set-semantics.md
Expand Up @@ -6,19 +6,19 @@ accessible when you need to make assertions about an array without considering
the order or duplicate items.

```js
expect([3, 2, 1], 'with set semantics to satisfy', [1]);
expect([3, 2, 1], 'with set semantics to satisfy', new Set([1, 2, 3]));
```

```js
expect([3, 2, 1], 'with set semantics to exhaustively satisfy', [1]);
expect([3, 2, 1], 'with set semantics to satisfy', new Set([1, 2]));
```

```output
expected [ 3, 2, 1 ] with set semantics to exhaustively satisfy [ 1 ]
expected [ 3, 2, 1 ] with set semantics to satisfy Set([ 1, 2 ])

Set([
3, // should be removed
2, // should be removed
2,
1
])
```
4 changes: 2 additions & 2 deletions documentation/index.md
Expand Up @@ -13,11 +13,11 @@ Add support to [Unexpected](http://unexpected.js.org) for testing [Set](https://
[![Dependency Status](https://david-dm.org/unexpectedjs/unexpected-set.svg)](https://david-dm.org/unexpectedjs/unexpected-set)

```js
expect(new Set([1, 2, 3]), 'to satisfy', [3, 4]);
expect(new Set([1, 2, 3]), 'to satisfy', new Set([1, 2, 3, 4]));
```

```output
expected Set([ 1, 2, 3 ]) to satisfy [ 3, 4 ]
expected Set([ 1, 2, 3 ]) to satisfy Set([ 1, 2, 3, 4 ])

Set([
1,
Expand Down
39 changes: 17 additions & 22 deletions lib/unexpected-set.js
Expand Up @@ -228,14 +228,18 @@ module.exports = {
}
);

expect.addAssertion('<Set> [not] to be empty', (expect, subject) => {
expect(subject.size, '[not] to equal', 0);
});
alexjeffburke marked this conversation as resolved.
Show resolved Hide resolved

expect.addAssertion(
[
'<Set> to have items [exhaustively] satisfying <any+>',
'<Set> to have items [exhaustively] satisfying <any>',
'<Set> to have items [exhaustively] satisfying <assertion>',
],
(expect, subject, nextArg) => {
expect.errorMode = 'nested';
expect(subject.size, 'not to equal', 0);
expect(subject, 'not to be empty');
expect.errorMode = 'bubble';

const subjectElements = [];
Expand All @@ -244,15 +248,14 @@ module.exports = {
});

const expected = [];
subject.forEach((subjectElement) => {
subjectElements.forEach((subjectElement) => {
if (typeof nextArg === 'string') {
expected.push(expect.it((s) => expect.shift(s, 0)));
} else if (typeof nextArg === 'function') {
expected.push(nextArg);
} else {
expected.push(nextArg);
}
});

return expect.withError(
() => expect(subjectElements, 'to [exhaustively] satisfy', expected),
(err) => {
Expand All @@ -279,21 +282,15 @@ module.exports = {
expect.addAssertion(
'<Set> to [exhaustively] satisfy <Set>',
(expect, subject, value) => {
const subjectElements = [];
subject.forEach((element) => {
subjectElements.push(element);
});
const valueElements = [];
value.forEach((element) => {
valueElements.push(element);
});
return expect(subject, 'to [exhaustively] satisfy', valueElements);
}
);

expect.addAssertion(
'<Set> to [exhaustively] satisfy <array-like>',
(expect, subject, valueElements) => {
const subjectElements = [];
subject.forEach((element) => {
subjectElements.push(element);
});
const promiseBySubjectIndexAndValueIndex = subjectElements.map(
() => new Array(valueElements.length)
);
Expand Down Expand Up @@ -327,12 +324,11 @@ module.exports = {
!promiseByValueIndexAndSubjectIndex.every((row) =>
row.some((promise) => promise.isFulfilled())
) ||
(expect.flags.exhaustively &&
!subjectElements.every((subjectElement, i) =>
promiseByValueIndexAndSubjectIndex.some((row) =>
row[i].isFulfilled()
)
))
!subjectElements.every((subjectElement, i) =>
promiseByValueIndexAndSubjectIndex.some((row) =>
row[i].isFulfilled()
)
)
) {
expect.fail({
diff(output, diff, inspect, equal) {
Expand Down Expand Up @@ -367,7 +363,6 @@ module.exports = {
subjectElements.length
);
if (
expect.flags.exhaustively &&
!promiseBySubjectIndexAndValueIndex[
subjectIndex
].some((promise, valueIndex) =>
Expand Down