98

I have an object that may be extended along my behavior under test, but I want to make sure that the original properties are still there.

var example = {'foo':'bar', 'bar':'baz'}

var result = extendingPipeline(example)
// {'foo':'bar', 'bar':'baz', 'extension': Function}

expect(result).toEqual(example) //fails miserably

I'd like to have a matcher that would pass in this case, along the lines of:

expect(result).toInclude(example)

I know that I can write a custom matcher, but it seems to me that this is such a common problem that a solution should be out there already. Where should I look for it?

iwein
  • 25,788
  • 10
  • 70
  • 111
  • I had a similar issue trying to compare arrays so I couldn't directly use jasmine.objectContaining which doesn't handle array as described in another answer, in the end I just used array.map on the expected result to get a object matching the example, leaving this here for consideration as an alternative. – Brandon Culley Aug 01 '18 at 20:13

5 Answers5

169

Jasmine 2.0

expect(result).toEqual(jasmine.objectContaining(example))

Since this fix: https://github.com/pivotal/jasmine/commit/47884032ad255e8e15144dcd3545c3267795dee0 it even works on nested objects, you just need to wrap each object you want to match partially in jasmine.objectContaining()

Simple example:

it('can match nested partial objects', function ()
{
    var joc = jasmine.objectContaining;
    expect({ 
        a: {x: 1, y: 2}, 
        b: 'hi' 
    }).toEqual(joc({
        a: joc({ x: 1})
    }));
});
jrharshath
  • 25,975
  • 33
  • 97
  • 127
Kamil Szot
  • 17,436
  • 6
  • 62
  • 65
  • Is there a way to do the same thing for an object containing different values and similar keys? – Siva Feb 09 '15 at 10:44
  • 3
    @Siva - Maybe you could try to compare results of `Object.keys(obj)` instead of your objects directly? – Kamil Szot Feb 10 '15 at 11:54
11

I've had the same problem. I just tried this code, it works for me :

expect(Object.keys(myObject)).toContain('myKey');
Chicna
  • 180
  • 1
  • 7
2

I don't think it is that common and I don't think you can find one. Just write one:

beforeEach(function () {
    this.addMatchers({
        toInclude: function (expected) {
            var failed;

            for (var i in expected) {
                if (expected.hasOwnProperty(i) && !this.actual.hasOwnProperty(i)) {
                    failed = [i, expected[i]];
                    break;
                }
            }

            if (undefined !== failed) {
                this.message = function() {
                    return 'Failed asserting that array includes element "'
                        + failed[0] + ' => ' + failed[1] + '"';
                };
                return false;
            }

            return true;
        }
    });
});
Wouter J
  • 41,455
  • 15
  • 107
  • 112
2

I thought that I would offer an alternative using modern javascript map and rest operator. We are able to omit properties using destructuring with rest operator. See further description in this article.

var example = {'foo':'bar', 'bar':'baz'}

var { extension, ...rest } = extendingPipeline(example)

expect(rest).toEqual(example)
Brandon Culley
  • 5,219
  • 1
  • 28
  • 28
1

jasmine.objectContaining() only works for a single layer.

expect(result).toMatchObject(example) checks that the object example that is passed in matches a subset of the properties of result.

sbgib
  • 5,580
  • 3
  • 19
  • 26
  • 2
    I think this instruction is referred to Jest. Is it right? **toMatchObject** is not available into Jasmine (at least up to version available now, which is version 3.9.0) – mginius Oct 12 '21 at 08:36