vendredi 26 mai 2017

Node testing - rewire and fakeredis on object oriented app

So I'm attempting to test an app that uses a redis backend and an OO type framework. Using models in the format below for various objects. I've provided a very cut down version of one of the models below.

class Tld {

/**
 * Creates an instance of Tld
 * @constructor
 * @param {string} tld The tld name
 */
constructor(tld) {
    this.identifier = tld
}


/**
 * Returns a promise that is fulfilled with an array of
 * tlds from redis tlds(zset) key
 *
 * @static
 * @param {Integer} [limit=-1] Number of tlds to return
 * @returns {Promise<Array>}
 *
 * @memberof Tld
 */
static getAll(limit = -1) {
    return new Promise((resolve, reject) => {
        redisClient.zrange("tlds", 0, limit, (err, tlds) => {
            resolve(tlds)
            reject(err)
        })
    })
}
/**
 * Add tld to the list of tlds
 *
 * @static
 * @param {String} tld
 * @returns {Promise<void>}
 *
 * @memberof Tag
 */
static addToList(tld, weight){
    return new Promise((resolve)=>{
         redisClient.zadd(`tlds`, weight, tld, ()=>{
             resolve()
        })
    })
}
}

This app is bootstrapped on load to populate redis with data from various APIs and other things, with a function similar to

Tld=require('../models/tld')
// tlds = loadDummyData()
// // tlds schema retreived from the dummy file
for(tld of tlds){
    tld = new Tld(tld)
    promises.push(Tld.addToList(tld.identifier, weight))
}

return Promise.all(promises)

It's all functional and cool, so I'm currently writing tests for the app, with mocha and chai. With a live redis instance, all is well, however I want to implement CI and I don't want to run redis on my build/test server, so I am looking to replace the redis instance using rewire and fakeredis.

My efforts so far include attempting to rewire the redis client on the bootstrap file and on the model, and bootstrapping (with dummy data) to a fake redis instance.

// Import testing modules
var assert = require('assert');
var chai = require('chai');
var expect = chai.expect;
chai.use(require('chai-ajv-json-schema'))
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);


// rewire redis to mocked  redis
var rewire = require("rewire");
var client = require("fakeredis").createClient();
var bootstrap = rewire('../bin/bootstrap')

var Tld = rewire('../models/tld')

bootstrap.__set__('redis', client)
Tld.__set__('redisClient', client)

bootstrap() // Would move this to a before() function in reality.


describe('Tld', function() {  
  describe('getAll', function() {
    it('should get all TLDs', function() {
        var results = Tld.getAll()

    return(expect(results).to.eventually.be.validWithSchema(
       tld_getall_schema))

    });
  });
})

However, in this case the TLD model is using the fake redis instance (Which is empty of data) but (I assume?) because the bootstrap function is including the Tld Model itself (Which will not be rewired at the point of including?) it's attempting to bootstrap to a live redis instance and is obviously erroring out.

1) Uncaught error outside test suite - Uncaught Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED 127.0.0.1:6379

so i threw a horrific attempt at a hack on:

bootstrap.__set__('redis', client)
Tld.__set__('redisClient', client)
// Inject rewired Tld model back into bootstrap:
bootstrap.__set__('Tld', Tld)
// bootstrap it.
bootstrap()

Which did basically no good at all.

So, How can I either replace the entire redis connection with rewire (without modifying my app code with a redis wrapper for example, because testing should be code-independant) Or, How can I fix what i'm doing here with regards to the bootstrapping to fake-redis.

Thanks for reading, hopefully you clever people can help me with a simple way to test the app :)

Aucun commentaire:

Enregistrer un commentaire