')
- .find('div')
- .append(input)
- .append(span);
-var pc = new PasswordCtrl();
-input.val('abc');
-pc.grade();
-expect(span.text()).toEqual('weak');
-$('body').empty();
-```
+describe('PasswordController', function() {
+ beforeEach(module('app'));
-In angular the controllers are strictly separated from the DOM manipulation logic and this results in
-a much easier testability story as the following example shows:
+ var $controller;
-```js
-function PasswordCtrl($scope) {
- $scope.password = '';
- $scope.grade = function() {
- var size = $scope.password.length;
- if (size > 8) {
- $scope.strength = 'strong';
- } else if (size > 3) {
- $scope.strength = 'medium';
- } else {
- $scope.strength = 'weak';
- }
- };
-}
-```
+ beforeEach(inject(function(_$controller_){
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ $controller = _$controller_;
+ }));
-and the test is straight forward:
+ describe('$scope.grade', function() {
+ var $scope, controller;
-```js
-var $scope = {};
-var pc = $controller('PasswordCtrl', { $scope: $scope });
-$scope.password = 'abc';
-$scope.grade();
-expect($scope.strength).toEqual('weak');
+ beforeEach(function() {
+ $scope = {};
+ controller = $controller('PasswordController', { $scope: $scope });
+ });
+
+ it('sets the strength to "strong" if the password length is >8 chars', function() {
+ $scope.password = 'longerthaneightchars';
+ $scope.grade();
+ expect($scope.strength).toEqual('strong');
+ });
+
+ it('sets the strength to "weak" if the password length <3 chars', function() {
+ $scope.password = 'a';
+ $scope.grade();
+ expect($scope.strength).toEqual('weak');
+ });
+ });
+});
```
-Notice that the test is not only much shorter, it is also easier to follow what is happening. We say
-that such a test tells a story, rather than asserting random bits which don't seem to be related.
+We've moved the duplication out and into the `beforeEach` block. Each individual test now
+only contains the code specific to that test, and not code that is general across all tests. As you
+expand your tests, keep an eye out for locations where you can use `beforeEach` to tidy up tests.
+`beforeEach` isn't the only function of this sort that Jasmine provides, and the [documentation
+lists the others](http://jasmine.github.io/1.3/introduction.html#section-Setup_and_Teardown).
-## Filters
+## Testing Filters
{@link ng.$filterProvider Filters} are functions which transform the data into a user readable
format. They are important because they remove the formatting responsibility from the application
logic, further simplifying the application logic.
@@ -273,12 +259,20 @@ myModule.filter('length', function() {
}
});
-var length = $filter('length');
-expect(length(null)).toEqual(0);
-expect(length('abc')).toEqual(3);
+describe('length filter', function() {
+ it('returns 0 when given null', function() {
+ var length = $filter('length');
+ expect(length(null)).toEqual(0);
+ });
+
+ it('returns the correct value when given a string of chars', function() {
+ var length = $filter('length');
+ expect(length('abc')).toEqual(3);
+ });
+});
```
-## Directives
+## Testing Directives
Directives in angular are responsible for encapsulating complex functionality within custom HTML tags,
attributes, classes or comments. Unit tests are very important for directives because the components
you create with directives may be used throughout your application and in many different contexts.
@@ -309,28 +303,28 @@ verify this functionality. Note that the expression `{{1 + 1}}` times will also
```js
describe('Unit testing great quotes', function() {
- var $compile;
- var $rootScope;
-
- // Load the myApp module, which contains the directive
- beforeEach(module('myApp'));
-
- // Store references to $rootScope and $compile
- // so they are available to all tests in this describe block
- beforeEach(inject(function(_$compile_, _$rootScope_){
- // The injector unwraps the underscores (_) from around the parameter names when matching
- $compile = _$compile_;
- $rootScope = _$rootScope_;
- }));
-
- it('Replaces the element with the appropriate content', function() {
- // Compile a piece of HTML containing the directive
- var element = $compile("
")($rootScope);
- // fire all the watches, so the scope expression {{1 + 1}} will be evaluated
- $rootScope.$digest();
- // Check that the compiled element contains the templated content
- expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
- });
+ var $compile,
+ $rootScope;
+
+ // Load the myApp module, which contains the directive
+ beforeEach(module('myApp'));
+
+ // Store references to $rootScope and $compile
+ // so they are available to all tests in this describe block
+ beforeEach(inject(function(_$compile_, _$rootScope_){
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ $compile = _$compile_;
+ $rootScope = _$rootScope_;
+ }));
+
+ it('Replaces the element with the appropriate content', function() {
+ // Compile a piece of HTML containing the directive
+ var element = $compile("
")($rootScope);
+ // fire all the watches, so the scope expression {{1 + 1}} will be evaluated
+ $rootScope.$digest();
+ // Check that the compiled element contains the templated content
+ expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
+ });
});
```
@@ -431,4 +425,3 @@ Otherwise you may run into issues if the test directory hierarchy differs from t
## Sample project
See the [angular-seed](https://github.com/angular/angular-seed) project for an example.
-