You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by sa...@apache.org on 2016/08/05 14:20:01 UTC

[34/37] incubator-milagro-mfa-js-lib git commit: Increase test coverage

Increase test coverage


Project: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/commit/4f0e481a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/4f0e481a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/4f0e481a

Branch: refs/heads/add-documentation
Commit: 4f0e481a0cb99976ad0d5327435cc2dfd2a93185
Parents: 0712ac9
Author: Boyan Bakov <bo...@certivox.com>
Authored: Mon Mar 21 15:49:17 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Mon Mar 21 18:00:04 2016 +0200

----------------------------------------------------------------------
 example/exampleJquery.html |   2 +-
 test/auth.js               | 266 ++++++++++++++++++++++++++++++
 test/index.html            |   4 +-
 test/index.js              | 346 ++++++++++++++++++++++++++--------------
 test/init.js               | 142 +++++++++++++++++
 5 files changed, 642 insertions(+), 118 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4f0e481a/example/exampleJquery.html
----------------------------------------------------------------------
diff --git a/example/exampleJquery.html b/example/exampleJquery.html
index c9459c1..5db8efe 100644
--- a/example/exampleJquery.html
+++ b/example/exampleJquery.html
@@ -122,7 +122,7 @@ and open the template in the editor.
         $(document).on('click', ".auth-accnumber", function (ev) {
           var userId, userPin, userAN;
           userId = $(ev.currentTarget).data('userid');
-					userPin = $(ev.currentTarget).parent("li").find("input.userPin").val();
+					userPin = $(ev.currentTarget).parents("li").find("input.userPin").val();
 					userAN = $(ev.currentTarget).prev("input.userAN").val();
 					
 					if (!mpin.checkAccessNumber(userAN)) {

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4f0e481a/test/auth.js
----------------------------------------------------------------------
diff --git a/test/auth.js b/test/auth.js
new file mode 100644
index 0000000..ab22fe3
--- /dev/null
+++ b/test/auth.js
@@ -0,0 +1,266 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+//if browser
+if (typeof require !== 'undefined') {
+  var expect = require('chai').expect;
+  var sinon = require('sinon');
+  var sinonChai = require('sinon-chai');
+  var mpinjs = require('../index');
+  var inits = require("./init");
+}
+var Errors, testData, testLocalstorage;
+
+Errors = inits.Errors;
+MPINAuth = inits.MPINAuth;
+MPIN = inits.MPIN;
+testData = inits.testData;
+testLocalstorage = inits.testLocalStorage;
+
+////////////////////////////////////////////////////////////authentication
+describe("# startAuthentication", function () {
+  var mpin, spy, serverUrl = "http://192.168.10.63:8005";
+
+  var testLocalstorage = {
+    "accounts": {
+      "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d32332031363a34393a31302e313039363734222c2022757365724944223a20227465737440746573742e636f6d222c202273616c74223a20223162396336353564343665323238373661333631373033353138616636363037227d": {
+        "regOTT": "4ac1cca55c09f6d4e47a253d8cd503b5",
+        "state": "STARTED"
+      }
+    }
+  };
+
+
+  var userId = "test@user.id";
+
+  beforeEach(function (done) {
+    var userPin = "userSecret";
+
+    mpin = new mpinjs({server: testData.serverUrl});
+    spy = sinon.spy();
+
+    sinon.stub(mpin, "getData", function () {
+      return testLocalstorage;
+    });
+    sinon.stub(mpin, "storeData");
+
+    spy = sinon.spy(mpin, "toHash");
+
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, testData.clientSettings);
+    stub.onCall(1).yields(null, testData.mpin);//mpinId
+    stub.onCall(2).yields(null, testData.cs1);//cs1
+    stub.onCall(3).yields(null, testData.cs2);//cs2
+
+    mpin.init(function (err, data) {
+      mpin.makeNewUser(userId);
+      mpin.startRegistration(userId, function (err1, data1) {
+        mpin.confirmRegistration(userId, function (err2, data2) {
+          mpin.finishRegistration(userId, userPin);
+          expect(spy.calledOnce).to.be.true;
+          expect(spy.calledWith(userPin)).to.be.true;
+          done();
+        });
+      });
+    });
+  });
+
+  afterEach(function () {
+    mpin.restore();
+    mpin.request.restore && mpin.request.restore();
+  });
+
+
+  it("should return error type " + Errors.missingUserId + " call without userId", function () {
+    var err = mpin.startAuthentication();
+    expect(err).to.deep.equal({code: 0, type: Errors.missingUserId});
+  });
+
+  it("should return error type " + Errors.userRevoked + " when timePermit1 request return status:401", function (done) {
+    var errData = {status: 500};
+    stub.onCall(4).yields({status: 401}, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(errData, null); //tp2 - return status 401 user Revoke
+    mpin.startAuthentication(userId, function (err, data) {
+      expect(err).to.deep.equal({code: 7, type: Errors.userRevoked});
+      done();
+    });
+  });
+
+  it("should return error type " + Errors.userRevoked + " when timePermit2 request return status:401", function (done) {
+    var errData = {status: 500};
+
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(errData, null); //tp2 - return status 401 user Revoke
+    mpin.startAuthentication(userId, function (err, data) {
+      expect(err).to.deep.equal(errData);
+      done();
+    });
+  });
+
+  it("should return error if have any other errors", function (done) {
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields({status: 401}, null); //tp2 - return status 401 user Revoke
+    mpin.startAuthentication(userId, function (err, data) {
+      expect(err).to.deep.equal({code: 7, type: Errors.userRevoked});
+      done();
+    });
+  });
+
+  it("should be ok ", function (done) {
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(null, testData.tp2); //tp2
+    mpin.startAuthentication(userId, function (err, data) {
+      expect(data).to.be.true;
+      done();
+    });
+  });
+});
+
+describe("# finishAuthentication", function () {
+  var mpin, spy, userId = "test@user.id", userPin = "userPIN";
+
+  beforeEach(function (done) {
+    mpin = new mpinjs({server: testData.serverUrl});
+    sinon.stub(mpin, "getData", function () {
+      return testLocalstorage;
+    });
+    sinon.stub(mpin, "storeData");
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, testData.clientSettings);
+    stub.onCall(1).yields(null, testData.mpin);//mpinId
+    stub.onCall(2).yields(null, testData.cs1);//cs1
+    stub.onCall(3).yields(null, testData.cs2);//cs2
+    done();
+    this.setupFlow = function (cb) {
+      mpin.init(function (err, data) {
+        mpin.makeNewUser(userId);
+        mpin.startRegistration(userId, function (err1, data1) {
+          mpin.confirmRegistration(userId, function (err2, data2) {
+            mpin.finishRegistration(userId, userPin);
+            cb();
+          });
+        });
+      });
+    };
+  });
+
+  afterEach(function () {
+    mpin.restore();
+    mpin.request.restore && mpin.request.restore();
+  });
+
+  it("should return error type " + Errors.wrongFlow + " when call finish Authentication w/o setupFlow", function (done) {
+    mpin.finishAuthentication(userId, "test", function (err, data) {
+      expect(err).to.deep.equal({code: 6, type: Errors.wrongFlow});
+      done();
+    });
+  });
+
+  it("should return error type " + Errors.wrongFlow + " when call finish Authentication w/o startAuthentication", function (done) {
+    this.setupFlow(function () {
+      mpin.finishAuthentication(userId, "test", function (err, data) {
+        expect(err).to.have.deep.property("type", Errors.wrongFlow);
+        done();
+      });
+    });
+  });
+
+  it("should return error type " + Errors.wrongPin + " when auth request fail with 401", function (done) {
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(null, testData.tp2); //tp2
+    stub.onCall(7).yields(null, testData.pass1); //pass1
+    stub.onCall(8).yields(null, testData.pass2); //pass2
+
+    stub.onCall(9).yields({status: 401}, null); //auth
+    this.setupFlow(function () {
+      mpin.startAuthentication(userId, function (err, data) {
+        mpin.finishAuthentication(userId, "test", function (err2, data2) {
+          expect(err2).to.have.deep.property("type", Errors.wrongPin);
+          done();
+        });
+      });
+    });
+  });
+
+  it("should return error type " + Errors.wrongPin + " when auth request fail with 410", function (done) {
+    var authOut = null;
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(null, testData.tp2); //tp2
+    stub.onCall(7).yields(null, testData.pass1); //pass1
+    stub.onCall(8).yields(null, testData.pass2); //pass2
+
+    stub.onCall(9).yields({status: 410}, null); //auth
+    this.setupFlow(function () {
+      mpin.startAuthentication(userId, function (err, data) {
+        mpin.finishAuthentication(userId, "test", function (err2, data2) {
+          expect(err2).to.have.deep.property("type", Errors.wrongPin);
+          done();
+        });
+      });
+    });
+  });
+
+  it("should hash pin if PIN is not an number", function (done) {
+    var authOut = null, spyHash, userPass = "testPass";
+
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(null, testData.tp2); //tp2
+    stub.onCall(7).yields(null, testData.pass1); //pass1
+    stub.onCall(8).yields(null, testData.pass2); //pass2
+
+    stub.onCall(9).yields(null, authOut); //auth
+    this.setupFlow(function () {
+      spyHash = sinon.spy(mpin, "toHash");
+      mpin.startAuthentication(userId, function (err, data) {
+        mpin.finishAuthentication(userId, userPass, function (err2, data2) {
+          expect(spyHash.calledOnce).to.be.true;
+          expect(spyHash.calledWith(userPass)).to.be.true;
+          done();
+        });
+      });
+    });
+  });
+
+  it("should return ok without data when response did not return such", function (done) {
+    var authOut = null;
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(null, testData.tp2); //tp2
+    stub.onCall(7).yields(null, testData.pass1); //pass1
+    stub.onCall(8).yields(null, testData.pass2); //pass2
+
+    stub.onCall(9).yields(null, authOut); //auth
+    this.setupFlow(function () {
+      mpin.startAuthentication(userId, function (err, data) {
+        mpin.finishAuthentication(userId, "test", function (err2, data2) {
+          expect(err2).to.be.a('null');
+          expect(data2).to.be.a('null');
+          done();
+        });
+      });
+    });
+  });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4f0e481a/test/index.html
----------------------------------------------------------------------
diff --git a/test/index.html b/test/index.html
index eba574f..1708549 100644
--- a/test/index.html
+++ b/test/index.html
@@ -32,7 +32,9 @@ and open the template in the editor.
 
 		</script>
 
-		<script src="index.js"></script> 
+		<script src="init.js"></script>
+		<script src="index.js"></script>
+		<script src="auth.js"></script>
 		<script>
 
       mocha.run();

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4f0e481a/test/index.js
----------------------------------------------------------------------
diff --git a/test/index.js b/test/index.js
index afa7924..1e836bb 100644
--- a/test/index.js
+++ b/test/index.js
@@ -22,39 +22,32 @@ if (typeof require !== 'undefined') {
   var expect = require('chai').expect;
   var sinon = require('sinon');
   var sinonChai = require('sinon-chai');
-  //used to generate test coverage with blanket
-  //  var mpinjs = require('../index');
-  var mpinjs = require('../dist/mpinjs');
+  var mpinjs = require('../index');
+  var inits = require("./init");
 }
+var Errors, testData, testLocalstorage, testLocalStorage2;
 
-var Errors = [];
-Errors[0] = "MISSING_USERID";
-Errors[1] = "INVALID_USERID";
-Errors[2] = "MISSING_PARAMETERS";
-Errors[3] = "IDENTITY_NOT_VERIFIED";
-
-var testLocalstorage = {
-  "accounts": {
-    "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d32332031363a34393a31302e313039363734222c2022757365724944223a20227465737440746573742e636f6d222c202273616c74223a20223162396336353564343665323238373661333631373033353138616636363037227d": {
-      "regOTT": "4ac1cca55c09f6d4e47a253d8cd503b5",
-      "state": "STARTED"
-    }
-  }
-};
-
-describe('# Constructor initialization without server Url.', function () {
-  it('should throw Error', function () {
+Errors = inits.Errors;
+MPINAuth = inits.MPINAuth;
+MPIN = inits.MPIN;
+testData = inits.testData;
+testLocalstorage = inits.testLocalStorage;
+testLocalStorage2 = inits.testLocalStorage2;
+
+
+describe("# Constructor initialization without sever Url.", function () {
+  it("should throw Error", function () {
     var mpin = new mpinjs();
     expect(mpin).to.be.an.instanceof(Error);
   });
 });
 
 //spy cases
-describe('# Normal iniatilization.', function () {
-  var mpin, spy, serverUrl = "http://192.168.10.63:8005";
+describe("# Normal initialization.", function () {
+  var mpin, spy;
 
   before(function () {
-    mpin = new mpinjs({server: serverUrl});
+    mpin = new mpinjs({server: testData.serverUrl});
     spy = sinon.spy();
 
     mpin.request = spy;
@@ -63,28 +56,23 @@ describe('# Normal iniatilization.', function () {
     });
   });
 
-  it('should call request method once', function () {
+  it("should call request method once", function () {
     mpin.init();
     expect(spy.calledOnce).to.be.true;
   });
 
-  it('should call request method with settingsUrl params', function () {
+  it("should call request method with settingsUrl params", function () {
     mpin.init();
-    expect(spy.calledWith({url: serverUrl + "/rps/clientSettings"})).to.be.true;
+    expect(spy.calledWith({url: testData.serverUrl + "/rps/clientSettings"})).to.be.true;
   });
 });
 
-describe('# Init method > clientSettings request.', function () {
-  var mpin, serverUrl = "http://192.168.10.63:8005";
+describe("# Init method > clientSettings request.", function () {
+  var mpin;
 
   before(function () {
-    mpin = new mpinjs({server: serverUrl});
+    mpin = new mpinjs({server: testData.serverUrl});
 
-    this.fakeRes = {
-      requestOTP: false,
-      mpinAuthServerURL: "http://192.168.10.63:8011/rps",
-      registerUrl: "http://192.168.10.63:8011/rps/user"
-    };
     sinon.stub(mpin, "getData", function () {
       return testLocalstorage;
     });
@@ -96,7 +84,7 @@ describe('# Init method > clientSettings request.', function () {
     done();
   });
 
-  it('should return error if init response is wrong', function (done) {
+  it("should return error if init response is wrong", function (done) {
     sinon.stub(mpin, 'request').yields({}, null);
     mpin.init(function (err, data) {
       expect(err).to.exist;
@@ -104,8 +92,8 @@ describe('# Init method > clientSettings request.', function () {
     });
   });
 
-  it('should store init response into internal property', function (done) {
-    sinon.stub(mpin, 'request').yields(null, JSON.stringify(this.fakeRes));
+  it("should store init response into internal property", function (done) {
+    sinon.stub(mpin, 'request').yields(null, testData.clientSettings);
     mpin.init(function (err, data) {
       expect(data).to.be.true;
       done();
@@ -114,43 +102,39 @@ describe('# Init method > clientSettings request.', function () {
 
 });
 
-describe('# makeNewUser checks.', function () {
-  var mpin, serverUrl = "http://192.168.10.63:8005";
+describe("# makeNewUser checks.", function () {
+  var mpin;
 
   before(function () {
-    mpin = new mpinjs({server: serverUrl});
+    mpin = new mpinjs({server: testData.serverUrl});
+
     sinon.stub(mpin, "getData", function () {
       return testLocalstorage;
     });
+//    sinon.stub(mpin, "addToUser");
   });
 
   after(function () {
     mpin.restore();
   });
 
-  it('should makeNewUser return error type ' + Errors[0] + ' when call without userId', function () {
+  it("should makeNewUser return error type " + Errors.missingUserId + " when call without userId", function () {
     var user = mpin.makeNewUser();
-    expect(user).to.deep.equal({code: 0, type: Errors[0]});
+    expect(user).to.deep.equal({code: 0, type: Errors.missingUserId});
   });
 
-  it('should store user into internal list', function () {
+  it("should store user into internal list", function () {
     var userId = "test@user.id";
     mpin.makeNewUser(userId);
     expect(mpin.checkUser(userId)).to.be.true;
   });
 });
 
-describe('# startRegistration.', function () {
-  var mpin, serverUrl = "http://192.168.10.63:8005";
+describe("# startRegistration.", function () {
+  var mpin;
 
   before(function () {
-    mpin = new mpinjs({server: serverUrl});
-
-    this.fakeRes = {
-      requestOTP: false,
-      mpinAuthServerURL: "http://192.168.10.63:8011/rps",
-      registerURL: "http://192.168.10.63:8011/rps/user"
-    };
+    mpin = new mpinjs({server: testData.serverUrl});
     sinon.stub(mpin, "getData", function () {
       return testLocalstorage;
     });
@@ -160,23 +144,22 @@ describe('# startRegistration.', function () {
     mpin.restore();
   });
 
-
-  it('should return error type ' + Errors[0] + ', call without userId', function (done) {
+  it("should return error type " + Errors.missingUserId + ", call without userId", function (done) {
     mpin.startRegistration(null, function (err, data) {
-      expect(err).to.deep.equal({code: 0, type: Errors[0]});
+      expect(err).to.deep.equal({code: 0, type: Errors.missingUserId});
       done();
     });
   });
 
-  it('should return error type ' + Errors[1] + ' if skip makeNewUser method.', function (done) {
+  it("should return error type " + Errors.invalidUserId + " if skip makeNewUser method.", function (done) {
     var userId = "test@user.id";
     mpin.startRegistration(userId, function (err, data) {
-      expect(err).to.deep.equal({code: 1, type: Errors[1]});
+      expect(err).to.deep.equal({code: 1, type: Errors.invalidUserId});
       done();
     });
   });
 
-  it('should return error type ' + Errors[2] + ' if skip init method.', function (done) {
+  it("should return error type " + Errors.missingParams + " if skip init method.", function (done) {
     var userId = "test@user.id";
     mpin.makeNewUser(userId);
     mpin.startRegistration(userId, function (err, data) {
@@ -185,14 +168,12 @@ describe('# startRegistration.', function () {
     });
   });
 
-  it('should return OK.', function (done) {
+  it("should return OK.", function (done) {
     var userId = "test@user.id";
 
     //mock for init method
-    sinon.stub(mpin, 'request').yields(null, this.fakeRes);
-
+    sinon.stub(mpin, 'request').yields(null, testData.clientSettings);
     mpin.init(function (err, data) {
-
       mpin.makeNewUser(userId);
       mpin.startRegistration(userId, function (err1, data1) {
         expect(data).to.exist;
@@ -203,27 +184,10 @@ describe('# startRegistration.', function () {
 });
 
 
-describe('# confirmRegistration.', function () {
-  var mpin, serverUrl = "http://192.168.10.63:8005";
-
+describe("# confirmRegistration.", function () {
+  var mpin;
   before(function () {
-    mpin = new mpinjs({server: serverUrl});
-
-    this.fakeRes = {
-      requestOTP: false,
-      mpinAuthServerURL: "http://192.168.10.63:8011/rps",
-      registerURL: "http://192.168.10.63:8011/rps/user",
-      signatureURL: "http://192.168.10.63:8011/rps/signature",
-      certivoxURL: "https://community-api.certivox.net/v3/"
-    };
-
-    this.fakeCs1 = {
-      clientSecretShare: "0421e379eb45e56ce699f0a7a83b683e84944b63fcc93a2834a4769ea40a28dc3f2064cd9d64846304999e00008b0838e246d3ea06d0013f1080c1027d54630ca9",
-      params: "mobile=0&expires=2015-12-03T12%3A47%3A23Z&app_id=e340a9f240e011e5b23b06df5546c0ed&hash_mpin_id=07a9af5af89d66b969be31d3d4e29c2a0a5ad4d3e30432eed9b3915dbf52230a&signature=33e8e987b07a2d9c9f3d98f68268870ef104cd0e0b9e02ba2c55e8bbf5190913&hash_user_id="
-    };
-    this.fakeCs2 = {
-      clientSecret: "0409ba1a247561ab16c35df3ad0ca9846db9968fa28757005335dc2ca35188b4f51521ac97d45bbdb3a8d1c0fdfe79ab29031054534df8b7cbac12e67e4e99d685"
-    };
+    mpin = new mpinjs({server: testData.serverUrl});
     sinon.stub(mpin, "getData", function () {
       return testLocalstorage;
     });
@@ -234,53 +198,35 @@ describe('# confirmRegistration.', function () {
     mpin.request.restore && mpin.request.restore();
   });
 
-
-  it('should return error type ' + Errors[0] + ' call without userId', function (done) {
+  it("should return error type " + Errors.missingUserId + " call without userId", function (done) {
     mpin.confirmRegistration(null, function (err, data) {
-      expect(err).to.deep.equal({code: 0, type: Errors[0]});
+      expect(err).to.deep.equal({code: 0, type: Errors.missingUserId});
       done();
     });
   });
 
-  it('should return error type ' + Errors[1] + '  if skip makeNewUser method.', function (done) {
+  it("should return error type " + Errors.invalidUserId + " if skip makeNewUser method.", function (done) {
     var userId = "test@user.id";
     mpin.confirmRegistration(userId, function (err, data) {
-      expect(err).to.have.deep.property('type', Errors[1]);
+      expect(err).to.have.deep.property('type', Errors.invalidUserId);
       done();
     });
   });
 
-  it('should return error type ' + Errors[2] + ' if skip init method.', function (done) {
+  it("should return error type " + Errors.missingParams + " if skip init method.", function (done) {
     var userId = "test@user.id";
     mpin.makeNewUser(userId);
     mpin.confirmRegistration(userId, function (err, data) {
-      expect(err).to.have.deep.property('type', Errors[2]);
+      expect(err).to.have.deep.property('type', Errors.missingParams);
       done();
     });
   });
-  /*
-   //start REGISTRATION >>>
-   it('should return error 4 if skip init method.', function (done) {
-   var userId = "test@user.id";
-   
-   sinon.stub(mpin, 'request').yields(null, this.fakeRes);
-   mpin.init(function (err, data) {
-   mpin.makeNewUser(userId);
-   //      sinon.stub(mpin, 'request').yields({status: 401}, null);
-   mpin.confirmRegistration(userId, function (err, data) {
-   console.log("err", err);
-   expect(err).to.have.deep.property('error', 4);
-   done();
-   });
-   });
-   });
-   */
-
-  it('should return error type ' + Errors[3] + ' identity not verify.', function (done) {
+
+  it("should return error type " + Errors.identityNotVerified + " identity not verify.", function (done) {
     var userId = "test@user.id", stub;
 
     stub = sinon.stub(mpin, 'request');
-    stub.onCall(0).yields(null, this.fakeRes);
+    stub.onCall(0).yields(null, testData.clientSettings);
     stub.onCall(1).yields(null, {});
     stub.onCall(2).yields({status: 401}, null);
 
@@ -288,7 +234,7 @@ describe('# confirmRegistration.', function () {
       mpin.makeNewUser(userId);
       mpin.startRegistration(userId, function (err1, data1) {
         mpin.confirmRegistration(userId, function (err2, data2) {
-          expect(err2).to.have.deep.property('type', Errors[3]);
+          expect(err2).to.have.deep.property('type', Errors.identityNotVerified);
           done();
         });
       });
@@ -296,14 +242,15 @@ describe('# confirmRegistration.', function () {
   });
 
   //start REGISTRATION >>> OK
-  it('should return OK', function (done) {
+  it("should return OK", function (done) {
     var userId = "test@user.id", stub;
+    //define global cripto
 
     stub = sinon.stub(mpin, 'request');
-    stub.onCall(0).yields(null, this.fakeRes);
+    stub.onCall(0).yields(null, testData.clientSettings);
     stub.onCall(1).yields(null, {});//mpinId
-    stub.onCall(2).yields(null, this.fakeCs1);//cs1
-    stub.onCall(3).yields(null, this.fakeCs2);//cs2
+    stub.onCall(2).yields(null, testData.cs1);//cs1
+    stub.onCall(3).yields(null, testData.cs2);//cs2
 
     mpin.init(function (err, data) {
       mpin.makeNewUser(userId);
@@ -315,12 +262,179 @@ describe('# confirmRegistration.', function () {
       });
     });
   });
+});
+
+
+describe("# finishRegistration", function () {
+  var mpin, spy, userId = "test@user.id";
+
+  beforeEach(function () {
+    mpin = new mpinjs({server: testData.serverUrl});
+
+    sinon.stub(mpin, "getData", function () {
+      return testLocalstorage;
+    });
+
+    sinon.stub(mpin, "storeData");
+  });
+
+  afterEach(function () {
+    mpin.restore();
+    mpin.request.restore && mpin.request.restore();
+  });
+
+  it("should return error type " + Errors.missingUserId + " call without userId", function () {
+    var err = mpin.finishRegistration();
+    expect(err).to.deep.equal({code: 0, type: Errors.missingUserId});
+  });
+
+  it("should call getUser (with userId arguments) to validate user state", function () {
+    spy = sinon.spy(mpin, "getUser");
+    mpin.finishRegistration(userId);
+    expect(spy.calledOnce).to.be.true;
+    expect(spy.calledWith(userId)).to.be.true;
+  });
+
+  it("should return error type " + Errors.wrongFlow + " when didn't activate identity", function () {
+    mpin.makeNewUser(userId);
+    var err2 = mpin.finishRegistration(userId);
+    expect(err2).to.have.deep.property('type', Errors.wrongFlow);
+  });
+
+  it("should hash pin if PIN is not an number", function (done) {
+    var userPin = "userSecret";
+    spy = sinon.spy(mpin, "toHash");
+
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, testData.clientSettings);
+    stub.onCall(1).yields(null, testData.mpin);//mpinId
+    stub.onCall(2).yields(null, testData.cs1);//cs1
+    stub.onCall(3).yields(null, testData.cs2);//cs2
+
+    mpin.init(function (err, data) {
+      mpin.makeNewUser(userId);
+      mpin.startRegistration(userId, function (err1, data1) {
+        mpin.confirmRegistration(userId, function (err2, data2) {
+          mpin.finishRegistration(userId, userPin);
+          expect(spy.calledOnce).to.be.true;
+          expect(spy.calledWith(userPin)).to.be.true;
+          done();
+        });
+      });
+    });
+  });
+
+  it("should save user state register", function (done) {
+    var userPin = "userSecret";
+
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, testData.clientSettings);
+    stub.onCall(1).yields(null, testData.mpin);//mpinId
+    stub.onCall(2).yields(null, testData.cs1);//cs1
+    stub.onCall(3).yields(null, testData.cs2);//cs2
+
+    mpin.init(function (err, data) {
+      mpin.makeNewUser(userId);
+      mpin.startRegistration(userId, function (err1, data1) {
+        mpin.confirmRegistration(userId, function (err2, data2) {
+          spy = sinon.spy(mpin, "addToUser");
+          mpin.finishRegistration(userId, userPin);
+          expect(spy.calledOnce).to.be.true;
+//          expect(spy.calledWith(userId, {token: "token", state: "REGISTERED"})).to.be.true;
+          done();
+        });
+      });
+    });
+  });
+});
 
 
 
+
+
+
+describe("# backward compatibility", function () {
+  var mpin;
+  beforeEach(function (done) {
+    mpin = new mpinjs({server: testData.serverUrl});
+    sinon.stub(mpin, "getData", function () {
+      return testLocalStorage2;
+    });
+    sinon.stub(mpin, 'request').yields(null, testData.clientSettings);
+
+    mpin.init(function (err, data) {
+      done();
+    });
+  });
+
+  it("read all identities and setup proper state", function () {
+    var users;
+    users = mpin.listUsers();
+    expect(users).to.have.length(2);
+    expect(users[0]).to.have.deep.property("state", "STARTED");
+    expect(users[1]).to.have.deep.property("state", "REGISTERED");
+  });
 });
 
+describe("# restartRegistration", function () {
+  var mpin;
+  beforeEach(function (done) {
+    mpin = new mpinjs({server: testData.serverUrl});
+    sinon.stub(mpin, "getData", function () {
+      return testLocalStorage2;
+    });
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, testData.clientSettings);//put user
+    
+    mpin.init(function (err, data) {
+      done();
+    });
+  });
 
-describe('# confirmRegistration.', function () {
+  afterEach(function () {
+    mpin.restore();
+    mpin.request.restore && mpin.request.restore();
+  });
+
+  it("should return error type " + Errors.missingUserId + " when call w/o user", function (done) {
+    mpin.restartRegistration(null, function (err, data) {
+      expect(err).to.have.deep.property("type", Errors.missingUserId);
+      done();
+    });
+  });
+
+  it("should return error type " + Errors.invalidUserId + " when call with unexisting user", function (done) {
+    mpin.restartRegistration("nonExistUser", function (err, data) {
+      expect(err).to.have.deep.property("type", Errors.invalidUserId);
+      done();
+    });
+  });
+
+  it("should return error type " + Errors.wrongFlow + " when call userId different state from started", function (done) {
+    mpin.restartRegistration("dddsre@mailinator.com", function (err, data) {
+      expect(err).to.have.deep.property("type", Errors.wrongFlow);
+      done();
+    });
+  });
+
+  it("should return error if request fail", function (done) {
+    sinon.stub(mpin, "storeData");
+
+    stub.onCall(1).yields({status: 401}, null);//put user
+    mpin.restartRegistration("aaa@bbb.com", function (err, data) {
+      expect(err).to.have.deep.property("status", 401);
+      done();
+    });
+  });
+
+  it("should return ok when request is ok", function (done) {
+    sinon.stub(mpin, "storeData");
+
+    stub.onCall(1).yields(null, true);//put user
+    mpin.restartRegistration("aaa@bbb.com", function (err, data) {
+      expect(data).to.be.ok;
+      done();
+    });
+  });
+});
 
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4f0e481a/test/init.js
----------------------------------------------------------------------
diff --git a/test/init.js b/test/init.js
new file mode 100644
index 0000000..4848170
--- /dev/null
+++ b/test/init.js
@@ -0,0 +1,142 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+//if browser
+var inits = function () {
+  var Errors, MPINAuth, MPIN, testData, testLocalStorage, testLocalStorage2;
+
+  Errors = [];
+  Errors.missingUserId = "MISSING_USERID";
+  Errors.invalidUserId = "INVALID_USERID";
+  Errors.missingParams = "MISSING_PARAMETERS";
+  Errors.identityNotVerified = "IDENTITY_NOT_VERIFIED";
+  Errors.identityMissing = "IDENTITY_MISSING";
+  Errors.wrongPin = "WRONG_PIN";
+  Errors.wrongFlow = "WRONG_FLOW";
+  Errors.userRevoked = "USER_REVOKED";
+
+  //overwrite global crypto function
+  MPINAuth = {};
+  MPINAuth.addShares = function () {
+    return "040a23a7e6d381a6dbd8b806013f07d40be36b42723ad3b1d986e4bbbe9ece83f421c504a4258cf87251af4ea7e847e4da46730034fc880f92d885c419716cb944";
+  };
+  MPINAuth.calculateMPinToken = function () {
+    return "04236eb28be98764e379049a2c4371752e7e3adc99a844800b9de2c34d2c70d95b07354c556276cbf79cee9e601807e6166d9bffedc3c1b1909ab5bf63330e2131";
+  };
+  MPINAuth.pass1Request = function () {
+    return {};
+  };
+  MPINAuth.pass2Request = function () {
+    return {};
+  };
+
+  MPIN = {};
+  MPIN.stringtobytes = function () {
+    return "";
+  }
+  MPIN.HASH_ID = function () {
+    return "";
+  }
+  MPIN.bytestostring = function () {
+    return "";
+  }
+
+  testData = {};
+  testData.serverUrl = "http://192.168.10.63:8005";
+  testData.clientSettings = {
+    requestOTP: false,
+    mpinAuthServerURL: "http://192.168.10.63:8011/rps",
+    registerURL: "http://192.168.10.63:8011/rps/user",
+    signatureURL: "http://192.168.10.63:8011/rps/signature",
+    certivoxURL: "https://community-api.certivox.net/v3/",
+    timePermitsURL: "http://192.168.10.63:8011/rps/timePermit"
+  };
+  testData.mpin = {
+    mpinId: "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30332d31352031333a34323a33362e393437303338222c2022757365724944223a20226d70696e4444222c202273616c74223a20226437373831313162633762653537323662666162633930353435396631643230227d"
+  };
+  testData.cs1 = {
+    clientSecretShare: "0421e379eb45e56ce699f0a7a83b683e84944b63fcc93a2834a4769ea40a28dc3f2064cd9d64846304999e00008b0838e246d3ea06d0013f1080c1027d54630ca9",
+    params: "mobile=0&expires=2015-12-03T12%3A47%3A23Z&app_id=e340a9f240e011e5b23b06df5546c0ed&hash_mpin_id=07a9af5af89d66b969be31d3d4e29c2a0a5ad4d3e30432eed9b3915dbf52230a&signature=33e8e987b07a2d9c9f3d98f68268870ef104cd0e0b9e02ba2c55e8bbf5190913&hash_user_id="
+  };
+  testData.cs2 = {
+    clientSecret: "0409ba1a247561ab16c35df3ad0ca9846db9968fa28757005335dc2ca35188b4f51521ac97d45bbdb3a8d1c0fdfe79ab29031054534df8b7cbac12e67e4e99d685"
+  };
+  testData.tp1 = {
+    "timePermit": "04145085669aa20607c0da730c01c707010e546bb81cf17abc29cacfef8e162b0f097b547c7058f6bd88e55cadc721b5721ee9730bfb10fa239c5bfacdb62fa3f4",
+    "signature": "39f9e16201d05dd3e369d43bd73cf0249e5bac01d5ff2975640d988e4a37b7f5",
+    "date": 16876
+  };
+  testData.tp2 = {
+    "timePermit": "040ff870574cb3c923410fdf33681beacd6ca6eeeb8858150efbf1241da9202c5604977ae285410df0d86a9976611b255a6fcbeeaf22bb398e4859ff3348bb4d87"
+  };
+  testData.pass1 = {
+    "y": "1dacb1f6830de09c0697485159da2ba4ed2908a8e24a85b886ff284306738b31"
+  };
+  testData.pass2 = {
+    "authOTT": "b0784ab9b6759953a3c6da85bdbdbaf3"
+  };
+  testData.auth = {
+    "authOTT": "b0784ab9b6759953a3c6da85bdbdbaf3"
+  };
+
+  testLocalStorage = {
+    "accounts": {
+      "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d32332031363a34393a31302e313039363734222c2022757365724944223a20227465737440746573742e636f6d222c202273616c74223a20223162396336353564343665323238373661333631373033353138616636363037227d": {
+        "regOTT": "4ac1cca55c09f6d4e47a253d8cd503b5",
+        "state": "STARTED"
+      }
+    }
+  };
+
+  testLocalStorage2 = {
+    "defaultIdentity": "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d30332031363a31333a32362e333030393938222c2022757365724944223a2022616161406262622e636f6d222c202273616c74223a20223237386166373433663465373034363764323334313936323262316333616231227d",
+    "version": "0.3",
+    "accounts": {
+      "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d30332031363a31333a32362e333030393938222c2022757365724944223a2022616161406262622e636f6d222c202273616c74223a20223237386166373433663465373034363764323334313936323262316333616231227d": {
+        "MPinPermit": "",
+        "token": "",
+        "regOTT": "b6216da7e3224e07eb4791815bcfcaa6"
+      },
+      "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d30382030383a35383a34302e373737373130222c2022757365724944223a2022646464737265406d61696c696e61746f722e636f6d222c202273616c74223a20223831373539623463313032363666646431616337323231326530643839393932227d": {
+        "MPinPermit": "042235a80c4c24f25a8a61758d3dac87d72b693c989ef95704c2ba51c7f4d98a631c912c9dc48435d9dd1af3dc17fa7d9e2af9beb16cc77bd38150c4697efdf232",
+        "token": "0412e48b124199f683e0ea6b8a1f1b073013dce21610de4b54cac74696e02003b1147d3ad7b4cef542c6ef61726dc4ffba039c90f7edd17cbeafb7c0737b41fc82",
+        "regOTT": "11adb574045ffe27e718d8b4dc665887",
+        "timePermitCache": {
+          "date": 16867,
+          "timePermit": "041c990c4087b5eeb7f4c2dbe5869794c208a22f63f6485a8905b35f542b2136a91cccf0696a6c60b2208ff1d3178da8fa661f7a52dda7db2738bfb1fe8b6cfa4b"
+        }
+      }
+    },
+    "deviceName": "winChrome"
+  };
+
+  return {
+    Errors: Errors,
+    MPINAuth: MPINAuth,
+    MPIN: MPIN,
+    testData: testData,
+    testLocalStorage: testLocalStorage,
+    testLocalStorage2: testLocalStorage2
+  };
+}();
+
+if (typeof module !== 'undefined' && typeof module.exports !== 'undefined')
+  module.exports = inits;
+else
+  window.inits = inits;