Translate

Friday, 30 March 2018

Testing a typescript class with mocha

Platform: nodejs
Install typescript, mocha for nodejs and the associated typings for mocha. 

The story starts with coming across some mocha problem caused by the usage of the implements keyword in Typescript in one of the forums for techies.

As ever, I picked it up and decided to write a mocha test to see what was the problem.

The test result revelations were as interesting as the Cambridge analytica fiasco and the subsequent handling of it in Singapore!

Some premise before I take you through to the bumper details!
.
An interface, in Typescript, serves as the blueprint much like in the other languages but it serves an additional purpose of defining how classes would implement them.

For instance, for a class that accepts a locale and a local time value, if the interface types the two parameters as a string and a number, scoped public respectively, then the class is forced to apply the same constraints. Even implementing the public property as private is not allowed.


// IClockTime.ts

export default interface IClockTime {
    new (time: number): IClock;
}

// IClock.ts

export default interface IClock {
    currentTime: number;
    locale: string;  
}

// Clock.ts

import IClock from './IClock'
import IClockTime from './IClockTime'
export default class Clock implements IClock {
    constructor(public currentTime:string) { 
        this.currentTime=currentTime
        }        
    public tellTime(t:IClockTime){
            return new t(this.currentTime);
        }
}

// AnotherClock.ts

import IClock from './IClock'
import IClockTime from './IClockTime'
export default class AnotherClock implements IClock {
    constructor (public currentTime: string, count: number) {
        this.currentTime=currentTime
        this.count=count
    }
    public tellTime(t:IClockTime){
            return new t(this.currentTime);
        }
}

// interfacestest.ts

import ClockTime from './IClockTime'
import AnotherClock from './anotherclock'
import Clock from './clock';
import {expect} from 'chai'
import 'mocha'
describe('an interface test', () => {  
it('to check time', () => {
var cc: ClockTime=Clock;
var cc1:ClockTime=AnotherClock
var ci = new cc(9.15,"GMT",12);
    expect(ci.tellTime(Clock)).to.equal('9:15');
  });
});


The tsc compiler is shrewd! It has noticed that the AnotherClock class has gone ahead and implemented some member of its own and not followed the blueprint provided by the IClock interface. This is much in the comfort zone of C# programmers.

It also correctly identifies what all AnotherClock has incorrectly implemented.

Modify the anotherClock class like so:

// AnotherClock.ts

import IClock from './IClock'
import IClockTime from './IClockTime'
export default class AnotherClock implements IClock {
   private _currentTime:number;
    private _locale:string;
    public get currentTime():number{
        return this._currentTime
    }
    public set currentTime(newtime:number){
        this._currentTime=newtime
    }
    private get locale():string{
        return this._locale
    }    
    private set locale(newlocale:string){
        this._locale=newlocale
    }
    constructor (currentTime: number, locale: string) {
        this.currentTime=currentTime
        this._locale=locale
    }
    public tellTime(){
            return this.currentTime;
        }
}

And you get errors from tsc that the property locale is not in sync with how the interface published it!


I will scope this to an example of a test of the class behavior and test whether the Clock returns the time expected of it, given the locale.

The Clock class, too, attempts its own tricks by supplying a string to a parameter of type IClockTime when it types the parameter of the checkLocale() method as a IClockTime rather than as a string. Change the parameter from t:IClockTime to t:string.

Modify the Clock class like so:

import IClock from './IClock'
import IClockTime from './IClockTime'
export default class Clock implements IClock {
    private _currentTime:number;
    private _locale:string;
    public get currentTime():number{
        return this._currentTime
    }
    public set currentTime(newtime:number){
        this._currentTime=newtime
    }
    constructor(currentTime:number, public locale:string) { 
        this.currentTime=currentTime
        this._locale=locale
        }        
    private checkLocaleTime(t:string){
        if (this._locale==="GMT")
        this.currentTime=this.currentTime-5.00
        
    }
    public tellTime(){
            this.checkLocaleTime(this.locale)
            console.log(this.currentTime)
            return this.currentTime.toString();
        }
}


Modify the test like so:

// interfacetest.ts

import ClockTime from './IClockTime'
import anotherClock from './anotherclock'
import Clock from './clock';
import IClock from './IClock'
import {expect} from 'chai'
import 'mocha'
describe('an interface test', () => {  
it('to check time', () => {
let cc= new Clock(9.15,"GMT");
    expect(cc.tellTime()).to.equal('9:15');
  });
});



Modify the expectation to match the GMT (approx.!) time and make the test pass!

Happy typescripting interfaces and classes for ES5!

Monday, 26 March 2018

The unhandled Promise rejection state and the others

Promises can be pleasant as well as vexing. In Javascript/node.js context, that is.

A promise can have three states: pending, fulfilled (resolved) or rejected.

Using a ES6 class, I managed to simplify the test that would demonstrate the three states and an additional, 'falsey' state!

First, the falsey state, as it can be confusing as an error message.


This message is caused when a Promise returns empty and is not handled in the test (mocha) either!

// mochatest.js

const assert=require('chai').assert
const asyncpromise=require('./asyncpromiserejection.js')
describe("asyncTests", () => {
it("handles Promise rejection",async ()=>{
    var t=new asyncpromise(false)
    await t.PTest().then(function () {
     console.log("Promise Resolved");
})
})        
});


// asyncpromiserejection.js

class asyncpromise{ 
    constructor(s){
        this.s=s
    }
PTest(){    
    var somevar = false;
    somevar=this.s;
    return new Promise(function (resolve, reject) {
        if (somevar === true)
            resolve();
        else
          // throw new Error("Promise rejcted")
            reject();
    });
}
}
module.exports=asyncpromise

As the else part in the code above does not do anything, it simply causes a promise rejection but since it is not handled in the test - there is no catch to handle the broken promise chain - it causes the message of a falsey.

Now, modify the test like so, by adding the catch block to handle the promise rejection state:

const assert=require('chai').assert
const asyncpromise=require('./asyncpromiserejection.js')
describe("asyncTests", () => {
it("handles Promise rejection",async ()=>{
    var t=new asyncpromise(false)
    await t.PTest().then(function () {
     console.log("Promise Resolved");
}).catch((error)=>{
    console.log("Promise rejected")
   // assert.equal(error.message,"Promise rejected")
})
})        
});




You can test for custom error messages returned by the rejected promise, like so:


class asyncpromise{ 
    constructor(s){
        this.s=s
    }
PTest(){    
    var somevar = false;
    somevar=this.s;
    return new Promise(function (resolve, reject) {
        if (somevar === true)
            resolve();
        else
           throw new Error("Promise rejcted")
           // reject();
    });
}
}
module.exports=asyncpromise


And the test, to include the assertion:

const assert=require('chai').assert
const asyncpromise=require('./asyncpromiserejection.js')
describe("asyncTests", () => {
it("handles Promise rejection",async ()=>{
    var t=new asyncpromise(false)
    await t.PTest().then(function () {
     console.log("Promise Resolved");
}).catch((error)=>{
   // console.log("Promise rejected")
    assert.equal(error.message,"Promise rejected")
})
})        
});



Make the test pass by simply correcting the typo in the error message!


Monday, 19 March 2018

Of a mocha test of a ES6 Fibonacci tree, the modulo operator, use case for getters and setters and undefined value of 0

ES6 has introduced some nice OO-like feel to javascript.

I, however, find it difficult to grasp the OO part of it in a language which says "Just use === when you wish to check and compare for both value and type"!

But with the ES6 specifications, the 'class' keyword and property getters and setters, javascript is looking to become more readable, intelligible and maintainable!

So, when I chanced upon a question in Stackoverflow dot com about a B Tree constructed on the Fibonacci series with 0 and 1 as root and subsequent values either to the left or to the right of the tree, I picked up the example to write a mocha test on it using ES6.

That is,
                                       0------1
                                      1--------2
                                     3----------5
                                    8-----------13
and so on.

So, the requirement says that we need a Node class with Left and Right node properties to contain the position of the node's value in the tree and a FibonacciTree class that would build the tree.

Remember, this is a test not the actual implementation of the tree so, the logic of decision-making to determine whether the value should be to the left or to the right of a node is left to the assertion of the test and is statically manipulated from the test ie., it is understood that since it is the test that knows its expectations as per "Arrange, Act, Assert" of the test, the conditional value (instanceOfB.X) is assumed.
Edit: You may need to use babel or target your config.json file to ES6 for the code to transpile.

The Fibonacci tree class is as below:

// fibonaccitree.js

var Node=require('./nodetree');
class fibonaccitree{
get X(){
    return this._X;
}
set X(newX){
    if (newX)
    this._X=newX;
}

buildTree(n){
       var node = new Node();
            console.log("Value of X is " +this._X)
            if (this._X % 2==0){
            node.left=n;
            }
            else if (this._X % 2!=0){
            node.right=n;
            }
       return node;
}
}

The node class that would contain the left and right values of a node is as below:

// nodetree.js

class nodetree {
    get right(){
        return this._right;
    }
    set right(rightValue){
        if (rightValue>=0)
        this._right=rightValue;
    }
    get left(){
        return this._left;
    }
    set left(leftValue){
        if (leftValue>=0)
        this._left=leftValue;
    }
}
module.exports=nodetree;

and the mocha test is as below:

// fibonaccitreetest.js

var A=require('./nodetree'),B=require('./fibonaccitree')
var assert=require('assert');
describe("Fibonacci tree Test", () => {
    var InstanceOfB=new B(); // Arrange
    var InstanceOfA=new A(); // Arrange
    beforeEach(() => {
          
             
    });
  afterEach(()=>{
    if (InstanceOfB.x==1){ // can use or not since test method also initializes. You may use either 
        InstanceOfB.X=2; // Arrange (Re-arrange) - edit: this is to check / ensure if /and even if the order of execution of test  methods change it will execute the if switch in code correctly
        //InstanceOfB = new B(); // Arrange (Re-arrange)
        //InstanceOfA = new A(); // Arrange (Re-arrange)
    }   
  })
    it('should check if the node is to the left of the binary tree', () => {
        InstanceOfB.X=2; // Arrange - can use or not since afterEach already initializes 
        var y=8;
        console.log("Value passed is " +y)
        var res = InstanceOfB.buildTree(y); // Act
        assert.equal(res.left,y); // Assert       
    });
    it('should check if the node is to the right of the binary tree', () => {
        InstanceOfB.X=1; // can use or not since afterEach already initializes 
        var z=13
        console.log("Value passed is " +z)
        var res = InstanceOfB.buildTree(z);
        assert.equal(res.right,z);
        
    });    
});

And the test result on node (node.js) is as in the below screenshot:


What is interesting in this example is the way the modulus operator in Javascript behaves.

If  a value of 0 is passed to the property 'X' in the fibonaccitree class then if (this._X%2==0) fails to evaluate correctly because the value of '0' supposedly gets interpreted as 'undefined', which is the reason for InstanceOfB.X=1; and InstanceOfB.X=2;


Note: To make the es6 code (only if you use import or export default keywords and the other es6 keywords) work in node.js, use the following steps:

1. npm install babel=preset-es2015 --save-dev
2. create a file called .babelrc in the root of your test/code/mocha folder with the value

{
  "presets": ["es2015"]

}

in the file.
3. Run the mocha test with "mocha --require followed by your test filename


Happy mocha-ing, ES6-ing, and modulo-ing javascript!