Skip to content

Commit

Permalink
Switched login logic over to the new login prompt factory pattern.
Browse files Browse the repository at this point in the history
  • Loading branch information
zakhenry committed Jul 16, 2015
1 parent ec4f334 commit ea2e9fb
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 45 deletions.
4 changes: 2 additions & 2 deletions app/bower.json
Expand Up @@ -32,9 +32,9 @@
"highlightjs": "~8.5.0",
"angular-material": "~0.10.0",
"toposort": "~0.3.1",
"angular-rest-adapter": "~1",
"angular-rest-adapter": "*",
"angular-http-progress": "*",
"angular-jwt-auth": "~1"
"angular-jwt-auth": "*"
},
"devDependencies": {
"angular-mocks": "~1.3",
Expand Down
2 changes: 1 addition & 1 deletion app/src/app/_partials/navigation.spec.ts
@@ -1,6 +1,6 @@


describe.only('Navigation', () => {
describe('Navigation', () => {

describe('Configuration', () => {

Expand Down
9 changes: 8 additions & 1 deletion app/src/app/guest/login/login-dialog.tpl.html
@@ -1,6 +1,13 @@
<md-dialog>
<md-dialog flex="50">
<md-dialog-content>

<md-toast ng-show="!!loginError">
<span flex>{{loginError}}</span>
<md-button ng-click="loginError = null">
Close
</md-button>
</md-toast>

<form novalidate name="loginForm">

<md-input-container class="md-icon-float" >
Expand Down
121 changes: 100 additions & 21 deletions app/src/app/guest/login/login.spec.ts
Expand Up @@ -2,28 +2,72 @@

describe('Login', () => {


let $q:ng.IQService,
fixtures = {
failLogin: false,
getLoginSuccessPromise(fail){
return {
promise: !fail ? $q.when('success') : $q.reject(new NgJwtAuth.NgJwtAuthException('error')),
};
}
};

describe('Configuration', () => {

let LoginController:ng.IControllerService,
$scope:ng.IScope,
$rootScope:ng.IRootScopeService,
$mdDialog:ng.material.IDialogService,
authService:NgJwtAuth.NgJwtAuthService
authService:NgJwtAuth.NgJwtAuthService,
deferredCredentials:ng.IDeferred<any>,
loginSuccess:{promise:ng.IPromise<any>}
;

beforeEach(() => {

module('app');
});


beforeEach(()=> {
inject(($controller, $rootScope, _ngJwtAuthService_, _$mdDialog_) => {

inject(($controller, _$rootScope_, _ngJwtAuthService_, _$mdDialog_, _$q_) => {
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
$mdDialog = _$mdDialog_;
authService = _ngJwtAuthService_;
LoginController = $controller(app.guest.login.namespace+'.controller', {$scope: $scope, $mdDialog: $mdDialog});
deferredCredentials = _$q_.defer();

$q = _$q_;

loginSuccess = fixtures.getLoginSuccessPromise(fixtures.failLogin);

LoginController = $controller(app.guest.login.namespace+'.controller', {
$scope: $scope,
$mdDialog: $mdDialog,
deferredCredentials:deferredCredentials,
loginSuccess: loginSuccess,
});
})
});

beforeEach(() => {

sinon.spy($mdDialog, 'hide');
sinon.spy($mdDialog, 'cancel');
sinon.spy($mdDialog, 'show');

});

afterEach(() => {

(<any>$mdDialog).hide.restore();
(<any>$mdDialog).cancel.restore();
(<any>$mdDialog).show.restore();

});

it('should be a valid controller', () => {

expect(LoginController).to.be.ok;
Expand All @@ -35,25 +79,29 @@ describe('Login', () => {

});

describe('dialog interactions', () => {
describe('dialog interactions - valid login', () => {

it('should cancel dialog when requested', () => { //@todo resolve why the cancel function is not firing the $mdDialog.show().catch() method

beforeEach(() => {

sinon.spy($mdDialog, 'hide');
sinon.spy($mdDialog, 'cancel');
sinon.spy($mdDialog, 'show');
(<any>$scope).cancelLoginDialog();

expect($mdDialog.cancel).to.have.been.called;
expect(deferredCredentials.promise).eventually.to.be.rejected;

$scope.$apply();
});

afterEach(() => {
it('should show the login dialog when prompted', () => {


authService.promptLogin();

(<any>$mdDialog).hide.restore();
(<any>$mdDialog).cancel.restore();
(<any>$mdDialog).show.restore();
expect($mdDialog.show).to.have.been.called;

});

it('should resolve the dialog when login credentials are passed', () => {
it('should resolve the deferred credentials when valid login credentials are passed, then hide the dialog on success', function(){


let creds = {
Expand All @@ -63,28 +111,59 @@ describe('Login', () => {

(<any>$scope).login(creds.username, creds.password);

expect($mdDialog.hide).to.have.been.calledWith(creds);
expect(deferredCredentials.promise).eventually.to.become(creds);

});
expect(loginSuccess.promise).eventually.to.become('success');

it('should cancel dialog when requested', () => {
$scope.$apply();

return loginSuccess.promise.then(() => {

(<any>$scope).cancelLoginDialog();
expect($mdDialog.hide).to.have.been.called;

});

expect($mdDialog.cancel).to.have.been.called;

});

it('should show the login dialog when prompted', () => {
after(() => {

fixtures.failLogin = true; //set up login failure for next describe block
});

authService.promptLogin();

expect($mdDialog.show).to.have.been.called;
});

describe('dialog interactions - invalid login', () => {


it('should show an error when invalid login credentials are passed', (done) => {

let creds = {
username: 'foo',
password: 'bar',
};

(<any>$scope).login(creds.username, creds.password);

expect(deferredCredentials.promise).eventually.to.become(creds);

expect(loginSuccess.promise).eventually.to.be.rejectedWith('error');

$scope.$apply();

loginSuccess.promise.finally(() => {

expect((<any>$scope).loginError).to.have.length.above(0);

done();

});


});


});


Expand Down
39 changes: 19 additions & 20 deletions app/src/app/guest/login/login.ts
Expand Up @@ -33,14 +33,17 @@ module app.guest.login {
) {

ngJwtAuthService
.registerLoginPromptFactory((existingUser, deferredCredentials:ng.IDeferred) => {
.registerLoginPromptFactory((deferredCredentials:ng.IDeferred<NgJwtAuth.ICredentials>, loginSuccessPromise:ng.IPromise<NgJwtAuth.IUser>, currentUser:NgJwtAuth.IUser): ng.IPromise<any> => {

let dialogConfig:ng.material.IDialogOptions = {
templateUrl: 'templates/app/guest/login/login-dialog.tpl.html',
controller: namespace+'.controller',
clickOutsideToClose: true,
locals : {
deferredCredentials: deferredCredentials
deferredCredentials: deferredCredentials,
loginSuccess: {
promise: loginSuccessPromise //nest the promise in a function as otherwise material will try to wait for it to resolve
},
}
};

Expand All @@ -49,16 +52,6 @@ module app.guest.login {
;

})
.registerCredentialPromiseFactory(function(existingUser){

let dialogConfig:ng.material.IDialogOptions = {
templateUrl: 'templates/app/guest/login/login-dialog.tpl.html',
controller: namespace+'.controller',
clickOutsideToClose: true,
};

return $mdDialog.show(dialogConfig);
})
.init(); //initialise the auth service (kicks off the timers etc)
}

Expand All @@ -68,38 +61,44 @@ module app.guest.login {
{
login(username:string, password:string):void;
cancelLoginDialog():void;
loginError:string;
}

class LoginController {

static $inject = ['$scope', '$mdDialog', 'deferredCredentials'];
static $inject = ['$scope', '$mdDialog', 'deferredCredentials', 'loginSuccess'];
constructor(
private $scope : IScope,
private $mdDialog:ng.material.IDialogService,
private deferredCredentials:ng.IDeferred
private deferredCredentials:ng.IDeferred<NgJwtAuth.ICredentials>,
private loginSuccess:{promise:ng.IPromise<NgJwtAuth.IUser>}
) {

$scope.loginError = '';

$scope.login = (username, password) => {

let credentials:NgJwtAuth.ICredentials = {
username: username,
password: password,
};

deferredCredentials.resolve(credentials);
deferredCredentials.resolve(credentials); //resolve the deferred credentials with the passed creds

deferredCredentials.promise
loginSuccess.promise
.then(
() => $mdDialog.hide(credentials), //on success hide the credentials
(err) => {
console.log('error'); //@todo display the error to the user. This will be something like password incorrect
(user) => $mdDialog.hide(user), //on success hide the dialog, pass through the returned user object
(err:Error) => {
if (err instanceof NgJwtAuth.NgJwtAuthException){
$scope.loginError = err.message; //if the is an auth exception, show the value to the user
}
}
)
;

};

$scope.cancelLoginDialog = () => $mdDialog.cancel();
$scope.cancelLoginDialog = () => $mdDialog.cancel('closed'); //allow the user to manually close the dialog

}

Expand Down

0 comments on commit ea2e9fb

Please sign in to comment.