Tyson Gern @tygern
gulp — gulp-karmagrunt — grunt-karmagulp — generator-gulp-angulargrunt — generator-angularAccording to Kent Beck...
Write a short failing test
Make the test pass in the simplest way possible
Eliminate duplication introduced in the previous step
Documents behavior of code
// adds one to the passed in value
function increment(number) {
  return number + 2;
}
            Leads to simple design
Allows frequent refactoring
Quickly add features
javascript testing framework
Function addStrings that adds integers passed as strings.
describe('addStrings', function () {
});
            
describe('addStrings', function () {
  it('correctly adds two numbers', function () {
  });
});
            
describe('addStrings', function () {
  it('correctly adds two numbers', function () {
    expect(addStrings('3', '5')).toEqual(8);
  });
});
            
describe('addStrings', function () {
  it('correctly adds two numbers', function () {
    expect(addStrings('3', '5')).toEqual(8);
    expect(addStrings('4', '6')).toEqual(10);
  });
});
            
describe('addStrings', function () {
  it('correctly adds two numbers', function () {
    expect(addStrings('3', '5')).toEqual(8);
    expect(addStrings('4', '6')).toEqual(10);
  });
});
            
              ReferenceError: addStrings is not defined
            
        
describe('addStrings', function () {
  it('correctly adds two numbers', function () {
    expect(addStrings('3', '5')).toEqual(8);
    expect(addStrings('4', '6')).toEqual(10);
  });
});
            
function addStrings() {
}
            
describe('addStrings', function () {
  it('correctly adds two numbers', function () {
    expect(addStrings('3', '5')).toEqual(8);
    expect(addStrings('4', '6')).toEqual(10);
  });
});
            
function addStrings() {
}
            
              Expected undefined to equal 8.
            
        
describe('addStrings', function () {
  it('correctly adds two numbers', function () {
    expect(addStrings('3', '5')).toEqual(8);
    expect(addStrings('4', '6')).toEqual(10);
  });
});
            
function addStrings() {
  return 8;
}
            
describe('addStrings', function () {
  it('correctly adds two numbers', function () {
    expect(addStrings('3', '5')).toEqual(8);
    expect(addStrings('4', '6')).toEqual(10);
  });
});
            
function addStrings() {
  return 8;
}
            
              Expected 8 to equal 10.
            
        
describe('addStrings', function () {
  it('correctly adds two numbers', function () {
    expect(addStrings('3', '5')).toEqual(8);
    expect(addStrings('4', '6')).toEqual(10);
  });
});
            
function addStrings(first, second) {
  return parseInt(first) + parseInt(second);
}
            
describe('addStrings', function () {
  it('correctly adds two numbers', function () {
    expect(addStrings('3', '5')).toEqual(8);
    expect(addStrings('4', '6')).toEqual(10);
  });
});
            
function addStrings(first, second) {
  return parseInt(first) + parseInt(second);
}
            Handle bad data. Count non-numbers as 0.
describe('addStrings', function () {
  //...
  it('treats non-numbers as 0', function () {
  });
});
            
function addStrings(first, second) {
  return parseInt(first) + parseInt(second);
}
            
describe('addStrings', function () {
  //...
  it('treats non-numbers as 0', function () {
    expect(addStrings('a', '6')).toEqual(6);
  });
});
            
function addStrings(first, second) {
  return parseInt(first) + parseInt(second);
}
            
describe('addStrings', function () {
  //...
  it('treats non-numbers as 0', function () {
    expect(addStrings('a', '6')).toEqual(6);
    expect(addStrings('2', '')).toEqual(2);
  });
});
            
function addStrings(first, second) {
  return parseInt(first) + parseInt(second);
}
            
describe('addStrings', function () {
  //...
  it('treats non-numbers as 0', function () {
    expect(addStrings('a', '6')).toEqual(6);
    expect(addStrings('2', '')).toEqual(2);
  });
});
            
function addStrings(first, second) {
  return parseInt(first) + parseInt(second);
}
            
            Expected NaN to equal 6.
          
        
describe('addStrings', function () {
  //...
  it('treats non-numbers as 0', function () {
    expect(addStrings('a', '6')).toEqual(6);
    expect(addStrings('2', '')).toEqual(2);
  });
});
            
function addStrings(first, second) {
  var firstNumber = parseInt(first);
  if(isNaN(firstNumber)) {
    firstNumber = 0;
  }
  return firstNumber + parseInt(second);
}
            
describe('addStrings', function () {
  //...
  it('treats non-numbers as 0', function () {
    expect(addStrings('a', '6')).toEqual(6);
    expect(addStrings('2', '')).toEqual(2);
  });
});
            
function addStrings(first, second) {
  var firstNumber = parseInt(first);
  if(isNaN(firstNumber)) {
    firstNumber = 0;
  }
  return firstNumber + parseInt(second);
}
            
            Expected NaN to equal 2.
          
        
describe('addStrings', function () {
  //...
  it('treats non-numbers as 0', function () {
    expect(addStrings('a', '6')).toEqual(6);
    expect(addStrings('2', '')).toEqual(2);
  });
});
            
function addStrings(first, second) {
  var firstNumber = parseInt(first);
  if(isNaN(firstNumber)) {
    firstNumber = 0;
  }
  var secondNumber = parseInt(second);
  if(isNaN(secondNumber)) {
    secondNumber = 0;
  }
  return firstNumber + secondNumber;
}
            
describe('addStrings', function () {
  //...
  it('treats non-numbers as 0', function () {
    expect(addStrings('a', '6')).toEqual(6);
    expect(addStrings('2', '')).toEqual(2);
  });
});
            
function addStrings(first, second) {
  var firstNumber = parseInt(first);
  if(isNaN(firstNumber)) {
    firstNumber = 0;
  }
  var secondNumber = parseInt(second);
  if(isNaN(secondNumber)) {
    secondNumber = 0;
  }
  return firstNumber + secondNumber;
}
            
describe('addStrings', function () {
  //...
  it('treats non-numbers as 0', function () {
    expect(addStrings('a', '6')).toEqual(6);
    expect(addStrings('2', '')).toEqual(2);
  });
});
            
function addStrings(first, second) {
  var firstNumber = parseInt(first);
  if(isNaN(firstNumber)) {
    firstNumber = 0;
  }
  var secondNumber = parseInt(second);
  if(isNaN(secondNumber)) {
    secondNumber = 0;
  }
  return firstNumber + secondNumber;
}
            
describe('addStrings', function () {
  //...
  it('treats non-numbers as 0', function () {
    expect(addStrings('a', '6')).toEqual(6);
    expect(addStrings('2', '')).toEqual(2);
  });
});
            
function addStrings(first, second) {
  function parseNumber(string) {
    var number = parseInt(string);
    return isNaN(number) ? 0 : number;
  }
  return parseNumber(first) + parseNumber(second);
}
            
describe('addStrings', function () {
  //...
  it('treats non-numbers as 0', function () {
    expect(addStrings('a', '6')).toEqual(6);
    expect(addStrings('2', '')).toEqual(2);
  });
});
            
function addStrings(first, second) {
  function parseNumber(string) {
    var number = parseInt(string);
    return isNaN(number) ? 0 : number;
  }
  return parseNumber(first) + parseNumber(second);
}
            javascript web framework
$scopeAngular synchronizes controllers and views with $scope.
  {{message}}
          +
angular.module('messaging')
  .controller('messaging.flashController', function ($scope) {
    $scope.message = 'hello';
  });
            =
  hello
            Angular uses dependency injection to provide objects with collaborators.
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             messagingService) {
  });
          Modules allow building application with modules.
angular.module('users', []);            //   greeterApplication
angular.module('twitterAdapter', []);   //         /     \
angular.module('messaging', [           //        /       \
  'twitterAdapter'                      //       /         \
]);                                     //  messaging     users
                                        //      |
angular.module('greeterApplication', [  //      |
  'users',                              //      |
  'messaging'                           // twitterAdapter
]);                                     //
          Start to build greeterApplication
Show initial greeting when the page loads
  
    {{message}}
  
          
describe('messaging.flashController', function () {
  beforeEach(module('messaging'));
  // tests go here
});
            
describe('messaging.flashController', function () {
  var $scope;
  beforeEach(module('messaging'));
  beforeEach(inject(function ($rootScope) {
    $scope = $rootScope.$new();
  }));
  // tests go here
});
            
describe('messaging.flashController', function () {
  var $scope;
  beforeEach(module('messaging'));
  beforeEach(inject(function ($rootScope, $controller) {
    $scope = $rootScope.$new();
    $controller('messaging.flashController', {
      $scope: $scope
    });
  }));
  // tests go here
});
            
describe('messaging.flashController', function () {
  var $scope, messagingService;
  beforeEach(module('messaging'));
  beforeEach(inject(function (..., _messagingService_) {
    $scope = $rootScope.$new();
    messagingService = _messagingService_;
    spyOn(messagingService, 'getMessage').and.returnValue('Hi!');
    $controller('messaging.flashController', {
      $scope: $scope,
      messagingService: messagingService
    });
  }));
  // tests go here
});
            
describe('messaging.flashController', function () {
  // setup
  describe('when the controller loads', function () {
    it('sets the message', function () {
    });
  });
});
            
describe('messaging.flashController', function () {
  // setup
  describe('when the controller loads', function () {
    it('sets the message', function () {
      expect($scope.message).toEqual('Hi!');
    });
  });
});
            
describe('messaging.flashController', function () {
  // setup
  describe('when the controller loads', function () {
    it('sets the message', function () {
      expect($scope.message).toEqual('Hi!');
      expect(messagingService.getMessage)
              .toHaveBeenCalledWith('initial');
    });
  });
});
            
describe('messaging.flashController', function () {
  // setup
  describe('when the controller loads', function () {
    it('sets the message', function () {
      expect($scope.message).toEqual('Hi!');
      expect(messagingService.getMessage)
              .toHaveBeenCalledWith('initial');
    });
  });
});
            
Expected undefined to equal 'Hi!'.
            
          
describe('messaging.flashController', function () {
  // setup
  describe('when the controller loads', function () {
    it('sets the message', function () {
      expect($scope.message).toEqual('Hi!');
      expect(messagingService.getMessage)
              .toHaveBeenCalledWith('initial');
    });
  });
});
            
Expected spy getMessage to have been called with [ 'initial' ] but it was never called.
            
          
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             messagingService) {
  });
          
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             messagingService) {
    $scope.message = messagingService.getMessage('initial');
  });
          
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             messagingService) {
    $scope.message = messagingService.getMessage('initial');
  });
          
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             messagingService) {
    $scope.message = messagingService.getMessage('initial');
  });
          
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             messagingService) {
    $scope.message = messagingService.getMessage('initial');
  });
          Change the message to prompt the user after 5 seconds
  
    {{message}}
  
          
describe('messaging.flashController', function () {
  // tests and setup
  describe('after waiting 5 seconds', function () {
    it('shows the \'prompt\' message', function () {
    });
  });
});
            
describe('messaging.flashController', function () {
  // tests and setup
  describe('after waiting 5 seconds', function () {
    it('shows the \'prompt\' message', function () {
      $scope.message = '';
      $timeout.flush(4900);
      expect($scope.message).toEqual('');
    });
  });
});
            
describe('messaging.flashController', function () {
  // tests and setup
  describe('after waiting 5 seconds', function () {
    it('shows the \'prompt\' message', function () {
      $scope.message = '';
      $timeout.flush(4900);
      expect($scope.message).toEqual('');
      $timeout.flush(200);
      expect($scope.message).toEqual('Hi!');
      expect(messagingService.getMessage)
              .toHaveBeenCalledWith('prompt');
    });
  });
});
            
describe('messaging.flashController', function () {
  // tests and setup
  describe('after waiting 5 seconds', function () {
    it('shows the \'prompt\' message', function () {
      $scope.message = '';
      $timeout.flush(4900);
      expect($scope.message).toEqual('');
      $timeout.flush(200);
      expect($scope.message).toEqual('Hi!');
      expect(messagingService.getMessage)
              .toHaveBeenCalledWith('prompt');
    });
  });
});
            
Expected '' to equal 'Hi!'.
            
          
describe('messaging.flashController', function () {
  // tests and setup
  describe('after waiting 5 seconds', function () {
    it('shows the \'prompt\' message', function () {
      $scope.message = '';
      $timeout.flush(4900);
      expect($scope.message).toEqual('');
      $timeout.flush(200);
      expect($scope.message).toEqual('Hi!');
      expect(messagingService.getMessage)
              .toHaveBeenCalledWith('prompt');
    });
  });
});
            
Expected spy getMessage to have been...
            
          
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             $timeout,
                                             messagingService) {
    $scope.message = messagingService.getMessage('initial');
  });
          
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             $timeout,
                                             messagingService) {
    $scope.message = messagingService.getMessage('initial');
    $timeout(function () {
      $scope.message = messagingService.getMessage('prompt');
    }, 5000);
  });
          
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             $timeout,
                                             messagingService) {
    $scope.message = messagingService.getMessage('initial');
    $timeout(function () {
      $scope.message = messagingService.getMessage('prompt');
    }, 5000);
  });
          
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             $timeout,
                                             messagingService) {
    $scope.message = messagingService.getMessage('initial');
    $timeout(function () {
      $scope.message = messagingService.getMessage('prompt');
    }, 5000);
  });
          
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             $timeout,
                                             messagingService) {
    function setMessage(type) {
      $scope.message = messagingService.getMessage(type);
    }
    setMessage('initial');
    $timeout(function () {
      setMessage('prompt');
    }, 5000);
  });
          
angular.module('messaging')
  .controller('messaging.flashController', function($scope,
                                             $timeout,
                                             messagingService) {
    function setMessage(type) {
      $scope.message = messagingService.getMessage(type);
    }
    setMessage('initial');
    $timeout(function () {
      setMessage('prompt');
    }, 5000);
  });
          Show the current user
  
    Welcome {{currentUser}}!
  
  
    {{message}}
  
          
describe('users.currentController', function () {
  var $scope, usersService, deferred;
  beforeEach(module('users'));
  beforeEach(inject(function ($rootScope, $controller, $q,
                              _usersService_) {
    $scope = $rootScope.$new();
    usersService = _usersService_;
    $controller('users.currentController', {
      $scope: $scope,
      usersService: usersService
    });
  }));
  // tests go here
});
            
describe('users.currentController', function () {
  var $scope, usersService, deferred;
  beforeEach(module('users'));
  beforeEach(inject(function ($rootScope, $controller, $q,
                              _usersService_) {
    $scope = $rootScope.$new();
    usersService = _usersService_;
    deferred = $q.defer();
    $controller('users.currentController', {
      $scope: $scope,
      usersService: usersService
    });
  }));
  // tests go here
});
            
describe('users.currentController', function () {
  var $scope, usersService, deferred;
  beforeEach(module('users'));
  beforeEach(inject(function ($rootScope, $controller, $q,
                              _usersService_) {
    $scope = $rootScope.$new();
    usersService = _usersService_;
    deferred = $q.defer();
    spyOn(usersService, 'getCurrent')
      .and.returnValue(deferred.promise);
    $controller('users.currentController', {
      $scope: $scope,
      usersService: usersService
    });
  }));
  // tests go here
});
            
describe('when the controller loads', function () {
  it('sets the current user', function () {
  });
});
            
describe('when the controller loads', function () {
  it('sets the current user', function () {
    expect($scope.currentUser).toEqual('Loading');
  });
});
            
describe('when the controller loads', function () {
  it('sets the current user', function () {
    expect($scope.currentUser).toEqual('Loading');
    deferred.resolve('@walken20');
  });
});
            
describe('when the controller loads', function () {
  it('sets the current user', function () {
    expect($scope.currentUser).toEqual('Loading');
    deferred.resolve('@walken20');
    $scope.$apply();
  });
});
            
describe('when the controller loads', function () {
  it('sets the current user', function () {
    expect($scope.currentUser).toEqual('Loading');
    deferred.resolve('@walken20');
    $scope.$apply();
    expect($scope.currentUser).toEqual('@walken20');
  });
});
            
describe('when the controller loads', function () {
  it('sets the current user', function () {
    expect($scope.currentUser).toEqual('Loading');
    deferred.resolve('@walken20');
    $scope.$apply();
    expect($scope.currentUser).toEqual('@walken20');
  });
});
            
Expected undefined to equal 'Loading'.
          
        
describe('when the controller loads', function () {
  it('sets the current user', function () {
    expect($scope.currentUser).toEqual('Loading');
    deferred.resolve('@walken20');
    $scope.$apply();
    expect($scope.currentUser).toEqual('@walken20');
  });
});
            
Expected undefined to equal '@walken20'.
          
        
angular.module('users')
  .controller('users.currentController', function($scope,
                                               usersService) {
  });
            
angular.module('users')
  .controller('users.currentController', function($scope,
                                               usersService) {
    $scope.currentUser = 'Loading';
  });
            
angular.module('users')
  .controller('users.currentController', function($scope,
                                               usersService) {
    $scope.currentUser = 'Loading';
    usersService.getCurrent().then(function (result) {
      $scope.currentUser = result;
    });
  });
            
angular.module('users')
  .controller('users.currentController', function($scope,
                                               usersService) {
    $scope.currentUser = 'Loading';
    usersService.getCurrent().then(function (result) {
      $scope.currentUser = result;
    });
  });
            
angular.module('users')
  .controller('users.currentController', function($scope,
                                               usersService) {
    $scope.currentUser = 'Loading';
    usersService.getCurrent().then(function (result) {
      $scope.currentUser = result;
    });
  });
            
angular.module('users')
  .controller('users.currentController', function($scope,
                                               usersService) {
    function setCurrentUser(user) {
      $scope.currentUser = user;
    }
    setCurrentUser('Loading');
    usersService.getCurrent().then(setCurrentUser);
  });
            
angular.module('users')
  .controller('users.currentController', function($scope,
                                               usersService) {
    function setCurrentUser(user) {
      $scope.currentUser = user;
    }
    setCurrentUser('Loading');
    usersService.getCurrent().then(setCurrentUser);
  });