In my last post I talked about some handy Jasmine matchers. Within hours after publishing that post, I discovered another interesting use for the matchers.

We were attempting to verify some parameters passed with an ajax query. The parameters have a nested structure, and we only cared about some of the parameters at the various levels.

One way to write such a test is to use toEqual and specify all of the parameters, even the ones we don’t care about. This over-constrains the test and makes it brittle in the face of unrelated changes.

Another way is to deconstruct the parameters and only test the parts of interest:

Verbose Test
it 'fetches with the correct filter', ->
args = view.collection.fetch.mostRecentCall.args[0]
expect(args['filters']['foo']).toEqual 'filter-value'
expect(args['bar']).toEqual 'value'

This works well, but is wordy and makes it hard to see the underlying structure of the expected parameters.

Using jasmine.objectContaining, we could instead write:

Succinct Test
it 'fetches with the correct filter', ->
expectedOptions =
filters: jasmine.objectContaining(foo: 'filter-value')
bar: 'value'

Using jasmine.objectContaining nested within another object works just fine here, and allows for a much cleaner test where the expected output has roughly the same structure as the data it’s matching. It’s easier to see what’s really expected this way.

jasmine.objectContaining is one of several asymmetric matchers, along with jasmine.any, jasmine.anything, jasmine.arrayContaining, and jasmine.stringMatching. You can even define your own asymmetric matcher by providing an object that has an asymmetricMatch function.

When Jasmine compares for equality, it tries very hard to compare them correctly. One of the options is to do an asymmetric comparison if appropriate; another is to recursively check object structure. Thus, it is possible to use any of the asymmetric matchers at any level of an object structure, and Jasmine will just do the right thing.