Search code examples
javascriptjasminegetterchainingbrackets

Javascript backwards-aware chaining without parenthesis e.g. expect(x).not.toBe()


Today I wanted to do something with chaining in a similar way to Jasmine: http://pivotal.github.io/jasmine/

Jasmine has a very fluid style of writing a test conditional, for example:

expect(result).not.toBe(85);

In my test I just wanted to add an and as some sugar coating that did something like:

createRegion('test').and.append()

So that was pretty simple (I am aware the following won't work in IE8<):

Layout.prototype.__defineGetter__('and', function() {
    return this;
});

But that got me interested in how jasmine is:

  • doing no-bracket chaining when I can't find any instance of defineProperty (IE8<) or __defineGetter__
  • cannot find where it has defined not
  • trying to imagine how the method chained after not is aware of it - I am assuming a variable is set like reverse = true in the not method so the proceeding method knows to reverse it's outcome?

How would you implement such behaviour, or otherwise do you know how jasmine has done it?


Solution

  • I took a look at the source, and this implementation of expect:

    jasmine.Spec.prototype.expect = function(actual) {
      var positive = new (this.getMatchersClass_())(this.env, actual, this);
      positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
      return positive;
    };
    

    So, the property not is the implementation of the same class, receiving this extra parameter to reverse the output:

    jasmine.Matchers = function(env, actual, spec, opt_isNot) {
      this.env = env;
      this.actual = actual;
      this.spec = spec;
      this.isNot = opt_isNot || false; // reverse option set
      this.reportWasCalled_ = false;
    };
    

    Finally, in jasmine.Matchers.matcherFn_, it uses it to reverse the result:

    if (this.isNot) {
        result = !result;
    }