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

Add assertion to be contained by #255

Closed
sunesimonsen opened this issue Jan 22, 2016 · 10 comments
Closed

Add assertion to be contained by #255

sunesimonsen opened this issue Jan 22, 2016 · 10 comments

Comments

@sunesimonsen
Copy link
Member

sunesimonsen commented Jan 22, 2016

I always implement this assertion as it is pretty useful:

expect(4, 'to be contained by', [1,2,3,4,5]);
@bruderstein
Copy link
Contributor

'to be contained in' rather than by? "contained by" sounds odd.

@sunesimonsen
Copy link
Member Author

@bruderstein I'm obviously not a native English speaker :-) So let's just use `to be contained in'.

@msiebuhr
Copy link
Contributor

msiebuhr commented Jul 6, 2016

Yay! I've been lacking a to be a su(b|per)set of for quite a few tests recently.

@msiebuhr
Copy link
Contributor

msiebuhr commented Jul 6, 2016

Here's my hacked together subset-check: Feel free to pifler as needed :)

expect.addAssertion('<any> to be a subset of <array>', function (expect, has, wantAtLeast) {
    if (!Array.isArray(has)) { has = [has]; }

    // See what's common between both sets
    var intersection = _.intersection(has, wantAtLeast);

    // If all input is in the common set, we're OK
    if (intersection.length !== has.length) {
        expect.fail({
            message: function (output) {
                return 'Expected', has, 'to be in', wantAtLeast;
            },
            diff: function (output, diff, inspect, equal) {
                return diff(has.sort(), intersection.sort());
            }
        });
    }
});

Generally, I've been missing some set theory in here; I'm currently writing a lot of API stubs where I have to check that returned data has one of some known values in certain properties.

Come to think of it, being able to do

expect(resp, 'to satisfy', {
    platform: expect.it('to be one of', ['ios', 'android', 'kindle']),
    ...
});

@papandreou
Copy link
Member

@msiebuhr That looks very useful!

http://unexpected.js.org/unexpected-set/ already supports <Set> to satisfy <array-like> which roughly means that all items in the set have to be satisfied by an item in the array. That might be a good place to land something like this.

@msiebuhr
Copy link
Contributor

msiebuhr commented Jul 7, 2016

You're welcome!

I'm not using sets (hello, Node 0.12.x) and I generally avoid using to satisfy, as its meaning can be quite ambiguous.

@papandreou
Copy link
Member

As for the last snippet, this works today:

expect(resp, 'to satisfy', {
    platform: expect.it('to equal', 'ios').or('to equal', 'android').or('to equal', 'kindle')
});

@papandreou
Copy link
Member

I'm not using sets (hello, Node 0.12.x)

The scope of unexpected-set includes exploring assertions with set semantics. It includes a Set polyfill, which is not applied globally, but which can be implicitly utilized via the with set semantics middle-of-the-rocket assertion.

and I generally avoid using to satisfy, as its meaning can be quite ambiguous.

Really? What sort of thing have you run into?

@msiebuhr
Copy link
Contributor

msiebuhr commented Jul 7, 2016

Really? What sort of thing have you run into?

In unexpected-moment, to satisfy is aliased to moment.isSame() (source), while unexpected-set quite obviously isn't that simple (~150 SLOC).

In general, I don't trust that I other people on the project can figure out the semantics of expect(result, 'to satisfy', some-value-or-other) without having to look in the documentation. For the general cases with objects and unexpected-sets list-of-assertions, it's usually obvious, but the exact semantics requires quite a few roundtrips to the documentation.

Having to be a subset of and to be a superset of would make it simple, explicit and straightforward.

platform: expect.it('to equal', 'ios').or('to equal', 'android').or('to equal', 'kindle')

A bit more stutter, but I guess that can do for now.

Also - it does seem one can build quite complex assertions with chains of .and and .or, but I can't quite find out how to make grouping explicit. Anything I missed?

@sunesimonsen
Copy link
Member Author

sunesimonsen commented Jul 9, 2016

The only documentation of expect.it is in to satisfy, we should probably try to explain the precedence a little bit better - it is only the indentation that gives a clue. The same indentation is also used when outputting expect.it in an error message.

platform: expect.it('to equal', 'ios').or('to equal', 'android').or('to equal', 'kindle')

This is horrible - you should just make a custom assertion if it is not provided by a plugin.

I don't want set operations in core, I think it belongs in unexpected-set. But strictly speaking it is also wrong to use arrays as sets, maybe another terminology could be used:

expect(['a', 'b', 'c'], 'to be contained in', ['a', 'b', 'c', 'b', 'd'])
expect(['a', 'b', 'c'], 'to contain', 'a', 'b')

The last assertion already exists but it is unfortunately varargs :-(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants