Search code examples
javascriptunit-testingjasminematcher

Is there any way to use Jasmine default matchers within custom matchers?


I have a custom matcher in some Jasmine test specs of the form:

this.addMatchers({
    checkContains: function(elem){
        var found = false;
        $.each( this.actual, function( actualItem ){

            // Check if these objects contain the same properties.
            found = found || actualItem.thing == elem;
        });
        return found;
    }
});

Of course, actualItem.thing == elem doesn't actually compare object contents- I have to use one of the more complex solutions in Object comparison in JavaScript.

I can't help but notice, though, that Jasmine already has a nice object equality checker: expect(x).toEqual(y). Is there any way to use that within a custom matcher? Is there any general way to use matchers within custom matchers?


Solution

  • Yes, it is slightly hacky but entirely possible.

    The first thing we need to do is make the Jasmine.Env class available. Personally I have done this in my SpecRunner.html since its already setup there anyway. On the load of my SpecRunner I have the following script that runs:

    (function() {
          var jasmineEnv = jasmine.getEnv();
          jasmineEnv.updateInterval = 1000;
    
          var trivialReporter = new jasmine.TrivialReporter();
    
          jasmineEnv.addReporter(trivialReporter);
    
          jasmineEnv.specFilter = function(spec) {
            return trivialReporter.specFilter(spec);
          };
    
          var currentWindowOnload = window.onload;
    
          window.onload = function() {
            if (currentWindowOnload) {
              currentWindowOnload();
            }
            execJasmine();
          };
    
          function execJasmine() {
            jasmineEnv.execute();
          };
    
        })();
    

    So after the execJasmine function declaration I push the jasmineEnv into the global namespace by adding this:

    this.jasmineEnv = jasmineEnv;
    

    Now, in any of my spec files I can access the jasmineEnv variable and that is what contains the matchers core code.

    Looking at toEqual specifically, toEqual calls the jasmine.Env.prototype.equals_ function. This means that in your customMatcher you can do the following:

    beforeEach(function(){
        this.addMatchers({
            isJasmineAwesome    : function(expected){
                return jasmineEnv.equals_(this.actual, expected);
            }
        });
    });
    

    Unfortunately, using this method will only give you access to the following methods:

    1. compareObjects_
    2. equals_
    3. contains_

    The rest of the matchers reside the jasmine.Matchers class but I have not been able to make that public yet. I hope this helps you out in someway or another