Often a project will want to encapsulate custom matching code for use across
multiple specs. Here is how to create a Jasmine-compatible custom matcher.
A custom matcher at its root is a comparison function that takes an actual
value and expected value. This factory is passed to Jasmine, ideally in a
call to beforeEach and will be in scope and available for all of the specs
inside a given call to describe. Custom matchers are torn down between specs.
The name of the factory will be the name of the matcher exposed on the return
value of the call to expect.
Custom matcher factories are passed a matchersUtil parameter, which has a
set of utility functions for matchers to use to perform tasks like
determining whether two objects are equal (see:
MatchersUtil for reference documentation).
By using MatchersUtil where appropriate, custom matchers can work with
custom equality testers
and custom object formatters
without any extra effort.
The compare function receives the value passed to expect() as
the first argument - the actual - and the value (if any) passed to
the matcher itself as second argument.
The compare function must return a result object with a pass
property that is a boolean result of the matcher. The pass
property tells the expectation whether the matcher was
successful (true) or unsuccessful (false). If the expectation
is called/chained with .not, the expectation will negate this
to determine whether the expectation is met.
If left undefined, the expectation will attempt to craft
a failure message for the matcher. However, if the return
value has a message property it will be used for a failed
expectation.
If you need more control over the negative comparison (the not case) than
the simple boolean inversion above, you can also have your matcher factory
include another key, negativeCompare alongside compare, for which the
value is a function to invoke when .not is used. This function/key is
optional.
You can also create your own async matchers. These are like regular custom
matchers except that they are used with expectAsync rather than expect
and the compare function is asynchronous.
The compare function should return a promise that resolves to a
value like the one returned by a regular matcher's compare function.
That can be done by explicitly returning a promise, as shown here,
or by declaring the function async.
The expected value should be a promise, but Jasmine does not
enforce that. It's a good idea to make sure custom async
matchers do something reasonable if a non-promise is passed
to expectAsync.
Registration works the same as with regular custom matchers, except that
you call jasmine.addAsyncMatchers to register the matcher and expectAsync
to use it.