unexpectedjs/unexpected

Support for checking nested properties

sazzer opened this issue · 10 comments

I might have missed it - apologies if so - but it would be very useful to support testing nested properties. Something like:

const value = {
    a: {
        b: {
            c: 1
        },
        d: {
            c: 2
        }
    }
};

expect(value, 'to have deep property', 'a.b.c', 1);

I'd use:

expect(value, 'to satisfy', { a: { b: { c: 1 } } });

But it's quite easy to implement to have deep property as a shorthand for that:

expect.addAssertion(
    '<object> to have deep property <string> <any>',
    (expect, subject, deepPropertyName, value) =>
        expect(
            subject,
            'to satisfy',
            deepPropertyName
                .split('.')
                .reverse()
                .reduce((acc, propertyName) => ({ [propertyName]: acc }), value)
        )
);

It produces a nice diff when there's a mismatch because to satisfy comes with one:

expected { a: { b: { c: 1 }, d: { c: 2 } } } to have deep property 'a.b.c', 2

{
  a: {
    b: {
      c: 1 // should equal 2
    },
    d: { c: 2 }
  }
}

'to satisfy' is perfect. I as surprised it wasn't an option when I looked.

In that case, can I suggest linking this from the docs for 'to have property' for people like me? :-)

Sent from my HUAWEI WAS-LX1A using FastHub

Do other assertion libraries support the a.b.c syntax, or how did you get the idea?

Oh, I see. A PR for adding that to the docs would be welcome. Here's the relevant file: https://github.com/unexpectedjs/unexpected/blob/master/documentation/assertions/object/to-have-property.md

Just a quick note to mention that jest-expect also has this and calls it key-paths. You can use it to assert the presence of a key in a structure but also validate the value by supplying a second argument.

This seems like a pretty useful feature, maybe we should support it.

Since . is also a valid character in field names, it would create ambiguity. When I (very briefly) worked with MongoDB I remember being angry about a.b.c in query objects meaning nested fields, which made it impossible to query a property with . in the name.

Yes you are probably right that the convenience is not worth ambiguity.

Let's just document why it doesn't work, as the OP suggested. Added here: #575