javascriptnode.jsinheritancejasmine-nodefrisby.js

How to extend frisby.js with more "expect" functions?


Is there a way to extend the Frisby.js module with custom expect methods? I don't want to modify the source code, these extensions are specific to my REST API. My goal is to avoid repeating common tests by combining them into a method.

The problem is that the Frisby.js module exports its methods with this code:

exports.create = function(msg) {
  return new Frisby(msg);
};

How would I add new methods to Frisby? This is more of a Javascript inheritance question as it applies to Node.js modules.

For example, a script to test the StackExchange API would have a lot of duplicate .expect clauses, like .expectHeader() and .expectJSONTypes(). I would like to combine these into a .expectSEwrapper() method. This method is unique to the StackExchange API so it wouldn't belong in Frisby.js. The script would look like this:

var frisby = require('frisby');

frisby.create('StackOverflow Info')
  .get('https://api.stackexchange.com/2.2/info?site=stackoverflow', {gzip: true})
  .expectStatus(200)
  .expectHeader('content-type', 'application/json; charset=utf-8')
  .expectHeader('content-encoding', 'gzip')
  .expectJSONTypes('', {
    items: Array,
    has_more: Boolean,
    quota_max: Number,
    quota_remaining: Number
  })
  .toss();

frisby.create('StackOverflow Badges')
  .get('https://api.stackexchange.com/2.2/badges?order=desc&sort=rank&site=stackoverflow', {gzip: true})
  .expectStatus(200)
  .expectHeader('content-type', 'application/json; charset=utf-8')
  .expectHeader('content-encoding', 'gzip')
  .expectJSONTypes('', {
    items: Array,
    has_more: Boolean,
    quota_max: Number,
    quota_remaining: Number
  })
  .expectJSONTypes('items.0', {
     badge_type: String,
     award_count: Number,
     rank: String,
     badge_id: Number,
     link: String,
     name: String
  })
  .toss();

I would like to have the script look more like this:

frisby.create('StackOverflow Info')
  .get('https://api.stackexchange.com/2.2/info?site=stackoverflow', {gzip: true})
  .expectSEwrapper()
  .toss();

frisby.create('StackOverflow Badges')
  .get('https://api.stackexchange.com/2.2/badges?order=desc&sort=rank&site=stackoverflow', {gzip: true})
  .expectSEwrapper()
  .expectJSONTypes('items.0', {
     badge_type: String,
     award_count: Number,
     rank: String,
     badge_id: Number,
     link: String,
     name: String
  })
  .toss();

This would mean adding a new method that looks like this:

frisby.expectSEwrapper = function() {
    return this.expectStatus(200)
               .expectHeader('content-type', 'application/json; charset=utf-8')
               .expectHeader('content-encoding', 'gzip')
               .expectJSONTypes('', {
                 items: Array,
                 has_more: Boolean,
                 quota_max: Number,
                 quota_remaining: Number
               });

But how do I add it to the Frisby prototype from inside of my script?


Solution

  • I came up with one solution that is basically a wrapper for Frisby.js. In a new Node module (which I called config.js), it extends the create() function:

    var frisby = require('frisby');
    
    // Customize Frisby.js for the StackExchange REST API
    exports.frisby = {
        create: function(describe) {
            var _frisby = frisby.create(describe);
    
            _frisby.expectSEwrapper = function() {
                return this.expectStatus(200)
                           .expectHeader('content-type', 'application/json; charset=utf-8')
                           .expectHeader('content-encoding', 'gzip')
                           .expectJSONTypes('', {
                               items: Array,
                               has_more: Boolean,
                               quota_max: Number,
                               quota_remaining: Number
                           });
            }
            return _frisby;
        }
    }
    

    Then, in my Frisby.js spec file, I require this module:

    var config = require('./config.js');
    var frisby = config.frisby;
    

    After this, I can write:

    frisby.create('StackOverflow Info')
      .get('https://api.stackexchange.com/2.2/info?site=stackoverflow', {gzip: true})
      .expectSEwrapper()
      .toss();