We will now start a new AngularJS blog project that uses public REST services created especially for this book. We will work on the blog project for the rest of this book. You can also download the project code from GitHub. We will start off by building the views and the controllers for those views.
Twitter Bootstrap is a free collection of HTML and CSS templates. We will build the AngularJS views with the help of Twitter Bootstrap to help cut development time. Once we have the views and controllers in place and understand their operation, we will focus on the model and REST services (in the next two chapters).
AngularJS views are defined by building templates (partials). Views in AngularJS are composed of HTML code with directives added, such as the ng-model
directive shown previously. AngularJS builds the views dynamically at runtime by merging the templates with the properties passed to the templates in the $scope
object. The end result is pure HTML code bound to the ng-view
directive, as explained back in Chapter 1. We will cover the ng-view
directive again in this chapter as a review.
Start a new HTML5 project in NetBeans and call it AngularJsBlog. Set up the folder structure as shown in Figure 5-1. Move the downloaded AngularJS, jQuery, and Bootstrap library files to the js/libs folder, as shown.
We’ll begin with the code for the index.html file. As you can see, we load the needed library files with the <script>
tag in the <head>
section of the page. The tag <div ng-view></div>
is where all dynamic content is inserted. As the user clicks on links in the application, existing content attached to the tag is removed and new dynamic content is then attached to that same tag:
<!-- chapter5/index.html -->
<!DOCTYPE html>
<html
lang=
"en"
ng-app=
"blogApp"
>
<head>
<title>
AngularJS Blog</title>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
>
<meta
http-equiv=
"Content-Type"
content=
"text/html; charset=UTF-8"
>
<script
src=
"js/libs/jquery-1.10.2.min.js"
></script>
<script
src=
"js/libs/angular.min.js"
></script>
<script
src=
"js/libs/angular-route.min.js"
></script>
<script
src=
"js/libs/angular-resource.min.js"
></script>
<script
src=
"js/libs/angular-cookies.min.js"
></script>
<script
src=
"js/app.js"
></script>
<script
src=
"js/controllers.js"
></script>
</head>
<body>
<div
ng-view
></div>
</body>
</html>
Next we will set up the controllers for our new blog application. The following code defines the blogControllers
module and the BlogCtrl
controller for that module. We will define more controllers on the blogControllers
module as we work on the blog application. For now, the controllers.js file is relatively small:
/* chapter5/controllers.js */
'use strict'
;
/* Controllers */
var
blogControllers
=
angular
.
module
(
'blogControllers'
,
[]);
blogControllers
.
controller
(
'BlogCtrl'
,
[
'$scope'
,
function
BlogCtrl
(
$scope
)
{
$scope
.
blogArticle
=
"This is a blog post about AngularJS.
We will cover how to build a blog and how to add
comments to the blog post."
;
}]);
Next is the code for the app.js file that starts the booting process for the blog application. This is where we define the route for the main page of the blog. As you can see, we define ngRoute
and blogControllers
as dependencies of the application at startup time, using inline array annotations. The two dependencies are injected into the application using DI and are available throughout the application when we need them. Any controllers attached to the blogControllers
module are accessible to the blogApp
module (the AngularJS application):
/* chapter5/app.js */
'use strict'
;
/* App Module */
var
blogApp
=
angular
.
module
(
'blogApp'
,
[
'ngRoute'
,
'blogControllers'
]);
blogApp
.
config
([
'$routeProvider'
,
'$locationProvider'
,
function
(
$routeProvider
,
$locationProvider
)
{
$routeProvider
.
when
(
'/'
,
{
templateUrl
:
'partials/main.html'
,
controller
:
'BlogCtrl'
});
$locationProvider
.
html5Mode
(
false
).
hashPrefix
(
'!'
);
}]);
The routes are defined in the application configuration block. For now, we will only define the main page of the blog. We define BlogCtrl
as the controller and 'partials/main.html'
as the template used for the main route. We will add more routes as we need them.
Now we will add a simple template file and test run the application before adding code to the template. Right-click the NetBeans project folder and add a new HTML page named main.html in the partials folder. Replace the generated HTML code with the code shown here:
<!-- chapter5/main.html -->
{{blogArticle}}
Right-click the project folder and select “Run” from the menu. If you set up the project correctly, the browser should open with the following text displayed: “This is a blog post about AngularJS. We will cover how to build a blog and how to add comments to the blog post.” This tells us our application is properly configured. Now we will use Twitter Bootstrap and HTML to build a menu and main page for our blog.
You should have already added bootstrap.min.js to the project. If you run into JavaScript errors related to Twitter Bootstrap, you can easily replace the bootstrap.min.js file with the nonminified bootstrap.js file distributed by Twitter. Using the nonminified version of the file allows the developer to place breakpoints in the Bootstrap JavaScript file and debug any related issues. We will only cover the basics of Twitter Bootstrap here. For more documentation and tutorials on Bootstrap, see the project site.
First, we need to add three more folders and some additional Twitter Bootstrap files to the project. We will add all the Bootstrap files here, although much of Bootstrap is not actually used in this project. Do the following:
<!--
chapter5
/
index
.
html
excerpt
-->
<
link
rel
=
"stylesheet"
href
=
"lib-css/bootstrap.min.css"
media
=
"screen"
/>
<
script
src
=
"js/libs/bootstrap.min.js"
><
/script>
Here is the completed index.html file:
<!-- chapter5/index.html complete file -->
<!DOCTYPE html>
<html
lang=
"en"
ng-app=
"blogApp"
>
<head>
<title>
Blog</title>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
>
<meta
http-equiv=
"Content-Type"
content=
"text/html; charset=UTF-8"
>
<link
rel=
"stylesheet"
href=
"lib-css/bootstrap.min.css"
media=
"screen"
/>
<script
src=
"js/libs/bootstrap.min.js"
></script>
<script
src=
"js/libs/jquery-1.10.2.min.js"
></script>
<script
src=
"js/libs/angular.min.js"
></script>
<script
src=
"js/libs/angular-route.min.js"
></script>
<script
src=
"js/libs/angular-resource.min.js"
></script>
<script
src=
"js/libs/angular-cookies.min.js"
></script>
<script
src=
"js/app.js"
></script>
<script
src=
"js/controllers.js"
></script>
</head>
<body>
<div
ng-view
></div>
</body>
</html>
Figure 5-2 shows the project file structure. Make sure your project is set up as shown. The added CSS files and fonts will give us access to many time-saving features of Twitter Bootstrap. We will now add a Bootstrap menu to our project.
The following are the contents of the menu.html file. Most of the code shown is clearly explained on the Bootstrap project site. The styles added to the menu here are defined in the bootstrap.min.css file added in the previous section. If you have questions on Bootstrap menus, please refer to the Bootstrap project documentation for a fuller explanation. Your menu.html file should look like this:
<!-- chapter5/menu.html -->
<nav
class=
"navbar navbar-inverse navbar-fixed-top"
role=
"navigation"
>
<!-- Brand and toggle get grouped for better mobile display -->
<div
class=
"container"
>
<div
class=
"navbar-header"
>
<button
type=
"button"
class=
"navbar-toggle"
data-toggle=
"collapse"
data-target=
".navbar-collapse"
>
<span
class=
"sr-only"
>
Toggle navigation</span>
<span
class=
"icon-bar"
></span>
<span
class=
"icon-bar"
></span>
<span
class=
"icon-bar"
></span>
</button>
<a
class=
"navbar-brand"
style=
"{{brandColor}}"
href=
"#!/"
>
Angular Blog</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div
class=
"collapse navbar-collapse"
>
<ul
class=
"nav navbar-nav"
>
<li
class=
"{{aboutActiveClass}}"
><a
href=
"#!about"
>
About</a></li>
<li
class=
""
>
<a
href=
"https://github.com/KenWilliamson"
>
Download Project Code</a></li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
</nav>
Here’s how to add the menu.html file inside the main.html file:
<!-- chapter5/main.html -->
<div
ng-include
src=
"'partials/menu.html'"
></div>
{{blogArticle}}
The first line shows the needed addition to main.html. As you see, we use the ng-include
directive to include the menu template inside the main template. This approach allows us to keep the menu completely separate from the other templates. Using this approach makes the code base easy to maintain and understand. We will now focus on using other Bootstrap styles to enhance our blog.
We will modify the BlogCtrl
controller and set a list of blog posts as a scope property named blogList
. The modified controllers.js code is shown here. The JSON list represents the data that will eventually be retrieved from a REST service. For now, however, we will just hardcode the JSON into the controller as mock data. There are more advanced ways to add mock data to an AngularJS application, but that is beyond the scope of this book. Let’s take a look at the controllers file:
/* chapter5/controllers.js */
'use strict'
;
/* Controllers */
var
blogControllers
=
angular
.
module
(
'blogControllers'
,
[]);
blogControllers
.
controller
(
'BlogCtrl'
,
[
'$scope'
,
function
BlogCtrl
(
$scope
)
{
$scope
.
blogList
=
[
{
"_id"
:
1
,
"date"
:
1400623623107
,
"introText"
:
"This is a blog post about AngularJS.
We will cover how to build"
,
"blogText"
:
"This is a blog post about AngularJS.
We will cover how to build a blog and how to add
comments to the blog post."
},
{
"_id"
:
2
,
"date"
:
1400267723107
,
"introText"
:
"In this blog post we will learn how to
build applications based on REST"
,
"blogText"
:
"In this blog post we will learn how to
build applications based on REST web services that
contain most of the business logic needed for the
application."
}
];
}]);
As you can see, there is no presentation logic in this code, and no data formatting is done in the controller. The date, for instance, is sent to the view as a long value that is a standard representation of a date in most programming languages. Trying to format the date in the controller would be an incorrect design that shouldn’t be used. AngularJS has many features that make formatting and presenting data easy; we’ll look at some of these next.
Now we will add some CSS3 to style our pages. Do the following:
/* chapter5/styles.css */
body
{
font-family
:
arial
;
font-size
:
12pt
;
color
:
#2a6496
;
}
.post-wrapper
{
float
:
left
;
width
:
100%
;
margin
:
5%
0
0
0
;
padding
:
0
0
0
0
;
}
.blog-post-label
{
float
:
left
;
width
:
100%
;
margin
:
10%
0
0
0
;
padding
:
0
0
0
0
;
text-align
:
center
;
font-weight
:
bold
;
font-size
:
16pt
;
}
.blog-post-outer
{
float
:
left
;
width
:
60%
;
margin
:
2%
0
2%
20%
;
padding
:
1%
;
background
:
#e0e0e0
;
border-radius
:
6px
;
-
moz
-
border-radius
:
6px
;
/* Firefox 3.6 and earlier */
border
:
darkgreen
solid
1px
;
}
.blog-intro-text
{
float
:
left
;
width
:
100%
;
margin
:
0
0
0
0
;
padding
:
0
0
0
0
;
text-align
:
center
;
}
.blog-read-more
{
float
:
left
;
width
:
100%
;
margin
:
2%
0
0
0
;
padding
:
0
0
0
0
;
text-align
:
center
;
}
Now modify the index.html file, adding the line shown here to load the newly created CSS file:
<!-- chapter5/index.html excerpt -->
<link
rel=
"stylesheet"
href=
"css/styles.css"
media=
"screen"
/>
The complete index.html file is shown here. Make sure your version of the file matches this one:
<!-- chapter5/index.html complete file -->
<!DOCTYPE html>
<html
lang=
"en"
ng-app=
"blogApp"
>
<head>
<title>
Blog</title>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
>
<meta
http-equiv=
"Content-Type"
content=
"text/html; charset=UTF-8"
>
<link
rel=
"stylesheet"
href=
"lib-css/bootstrap.min.css"
media=
"screen"
/>
<script
src=
"js/libs/jquery-1.10.2.min.js"
></script>
<script
src=
"js/libs/bootstrap.min.js"
></script>
<script
src=
"js/libs/angular.min.js"
></script>
<script
src=
"js/libs/angular-route.min.js"
></script>
<script
src=
"js/libs/angular-resource.min.js"
></script>
<script
src=
"js/libs/angular-cookies.min.js"
></script>
<link
rel=
"stylesheet"
href=
"css/styles.css"
media=
"screen"
/>
<script
src=
"js/app.js"
></script>
<script
src=
"js/controllers.js"
></script>
</head>
<body>
<div
ng-view
></div>
</body>
</html>
You must modify the main.html template to make use of the new styles and to add proper presentation logic for displaying blog posts and formatting data. Modify your main.html to match the code shown here. The second line, <div id="container" class="container">
, sets up a Bootstrap container and is standard practice with Twitter Bootstrap:
<!-- chapter5/main.html -->
<div
ng-include
src=
"'partials/menu.html'"
></div>
<div
id=
"container"
class=
"container"
>
<div
class=
"blog-post-label"
>
Blog Posts</div>
<div
class=
"post-wrapper"
>
<div
ng-repeat=
"blogPost in blogList"
>
<div
class=
"blog-post-outer"
>
<div
class=
"blog-intro-text"
>
Posted: {{blogPost.date | date:'MM/dd/yyyy @ h:mma'}}</div>
<div
class=
"blog-intro-text"
>
{{blogPost.introText}}</div>
<div
class=
"blog-read-more"
>
<a
href=
"#!blogPost/{{blogPost._id}}"
>
Read More</a>
</div>
</div>
</div>
</div>
</div>
The Bootstrap container handles much of the page styling for various screen sizes to make the page responsive for any screen size on any device. Inside the container we use the CSS that was added in the styles.css file. We won’t focus much on the custom CSS, because it is not specific to AngularJS and is covered in many other books on Cascading Style Sheets.
We will, however, take a look at the AngularJS directives that allow us to build the presentation logic in the view and handle formatting. The line <div ng-repeat="blogPost in blogList">
is very important to understanding AngularJS views. The directive ng-repeat
works like a for
loop, iterating over the list of blog posts in the scope property blogList
.
Each iteration through the list gives access to each item in the list through the variable blogPost
. We use the line {{blogPost.introText}}
to display the intro text (the value of the introText
property of the blogPost
variable).
Another line that is very important is the HTML template binding {{blogPost.date | date:'MM/dd/yyyy @ h:mma'}}
, which allows us to format the date in the view, where it should be formatted. As I stated previously, there are many features of AngularJS for formatting data, and this is just one. As you can see, the template code is simple and easy to understand.
We will now add a controller, route, and view to display the individual blog post when a user clicks on the “View More” link. If you look closely, you can see that the link passes blogPost.id
as a path parameter argument to a new route, /blogPost. We will now add the needed code to view a blog post.
To add the extra functionality, first append this CSS code to the end of the styles.css file:
/* chapter5/styles.css excerpt */
.blog-entry-wrapper
{
float
:
left
;
width
:
100%
;
margin
:
1%
0
0
0
;
padding
:
0
0
0
0
;
}
.blog-entry-outer
{
float
:
left
;
width
:
60%
;
margin
:
2%
0
2%
20%
;
padding
:
1%
;
background
:
#e0e0e0
;
border-radius
:
6px
;
-
moz
-
border-radius
:
6px
;
/* Firefox 3.6 and earlier */
border
:
darkgreen
solid
1px
;
}
.blog-comment-wrapper
{
float
:
left
;
width
:
50%
;
an
HTML5
project
margin
:
2%
0
2%
25%
;
padding
:
1%
;
border-radius
:
6px
;
-
moz
-
border-radius
:
6px
;
/* Firefox 3.6 and earlier */
border
:
darkgreen
solid
1px
;
}
.blog-entry-comments
{
float
:
left
;
width
:
96%
;
margin
:
2%
0
2%
2%
;
padding
:
1%
;
background
:
#f5e79e
;
border-radius
:
6px
;
-
moz
-
border-radius
:
6px
;
/* Firefox 3.6 and earlier */
border
:
darkgreen
solid
1px
;
}
.blog-comment-label
{
float
:
left
;
width
:
100%
;
margin
:
1%
0
0
0
;
padding
:
0
0
0
0
;
text-align
:
center
;
font-weight
:
bold
;
font-size
:
16pt
;
}
Then add this code to the bottom of the controllers.js file:
/* chapter5/controllers.js excerpt */
blogControllers
.
controller
(
'BlogViewCtrl'
,
[
'$scope'
,
'$routeParams'
,
function
BlogViewCtrl
(
$scope
,
$routeParams
)
{
var
blogId
=
$routeParams
.
id
;
var
blog1
=
{
"_id"
:
1
,
"date"
:
1400623623107
,
"introText"
:
"This is a blog post about AngularJS.
We will cover how to build"
,
"blogText"
:
"This is a blog post about AngularJS.
We will cover how to build a blog and how to add
comments to the blog post."
,
"comments"
:
[
{
"commentText"
:
"Very good post. I love it."
},
{
"commentText"
:
"When can we learn services."
}
]
};
var
blog2
=
{
"_id"
:
2
,
"date"
:
1400267723107
,
"introText"
:
"In this blog post we will learn how to
build applications based on REST"
,
"blogText"
:
"In this blog post we will learn how to
build applications based on REST web services that
contain most of the business logic needed for the application."
,
"comments"
:
[
{
"commentText"
:
"REST is great. I want to know more."
},
{
"commentText"
:
"Will we use Node.js for REST services?."
}
]
};
if
(
blogId
===
'1'
){
$scope
.
blogEntry
=
blog1
;
}
else
if
(
blogId
===
'2'
){
$scope
.
blogEntry
=
blog2
;
}
}]);
Next, add a new template file named blogPost.html in the partials folder and replace the generated code with the code shown here:
<!-- chapter5/blogPost.html -->
<div
ng-include
src=
"'partials/menu.html'"
></div>
<div
id=
"container"
class=
"container"
>
<div
class=
"blog-post-label"
>
Blog Entry</div>
<div
class=
"blog-entry-wrapper"
>
<div
class=
"blog-intro-text"
>
Posted: {{blogEntry.date| date:'MM/dd/yyyy @ h:mma'}}</div>
<div
class=
"blog-entry-outer"
>
{{blogEntry.blogText}}</div>
<div
class=
"blog-comment-wrapper"
>
<div
class=
"blog-comment-label"
>
Blog Comments</div>
<div
class=
"blog-entry-comments"
ng-repeat=
"comment in
blogEntry.comments"
>
{{comment.commentText}}</div>
</div>
</div>
</div>
And add this code to the route provider section of app.js:
/* chapter5/app.js excerpt */
.
when
(
'/blogPost/:id'
,
{
templateUrl
:
'partials/blogPost.html'
,
controller
:
'BlogViewCtrl'
The complete route definition is shown here:
/* chapter5/app.js excerpt - complete route */
blogApp
.
config
([
'$routeProvider'
,
'$locationProvider'
,
function
(
$routeProvider
,
$locationProvider
)
{
$routeProvider
.
when
(
'/'
,
{
templateUrl
:
'partials/main.html'
,
controller
:
'BlogCtrl'
}).
when
(
'/blogPost/:id'
,
{
templateUrl
:
'partials/blogPost.html'
,
controller
:
'BlogViewCtrl'
});
$locationProvider
.
html5Mode
(
false
).
hashPrefix
(
'!'
);
}]);
As you can see, the effort required to add a new page was minimal. If you look at the route definition, you’ll see the id
passed as a path parameter argument. Look at the new controller and you can see how we handle the id
parameter. Since we do not yet have REST services in place, we hardcoded the JSON for the two blog posts into the controller.
Once we retrieve the passed id
from $routeParams
, we use that to determine which blog entry to set as a scope property. Notice that we never actually set a scope property until we know which blog entry gets sent to the view. Notice also that blog1
and blog2
are defined as local variables. Only the variables needed in the page are set as scope properties.
Now let’s run the project to test our work. Right-click the project node and select “Run” from the menu. If you made all the changes correctly, you should see the screen shown in Figure 5-3. If you get a different result, go back over the changes in this chapter and verify that you made all the needed modifications.
If you have problems that you can’t resolve, download the project code from GitHub and run that code. Once the project is running, click the “Read More” link on the first blog post. You should then see the screen shown in Figure 5-4. Click the “Read More” link on the second blog post, and you should see a similar page.
We will use Karma now to test our view. From the root of the Chapter 5 project, create a JSON file named package.json and add the following contents. The package.json file is used as a configuration file for Node.js, as mentioned in Chapter 4:
{ "name": "package.json", "devDependencies": { "karma": "*", "karma-chrome-launcher": "*", "karma-firefox-launcher": "*", "karma-jasmine": "*", "karma-junit-reporter": "*", "karma-coverage": "*" } }
Open a command-line window on your system, and navigate to the root of the Chapter 5 project. You should see the package.json file when you list out the files in the folder. Now type the following command to install the Node.js dependencies defined in the package.json file. This is the same process described in Chapter 4:
npm install
Now we will create a new Karma configuration file named karma.conf.js inside the project’s test folder, as we did in Chapter 4. Do the following:
Edit the new karma.conf.js file and add the code shown here:
/* chapter5/karma.conf.js */
module
.
exports
=
function
(
config
)
{
config
.
set
({
basePath
:
'../'
,
files
:
[
"public_html/js/libs/angular.min.js"
,
"public_html/js/libs/angular-mocks.js"
,
"public_html/js/libs/angular-route.min.js"
,
"public_html/js/*.js"
,
"test/**/*Spec.js"
],
exclude
:
[
],
autoWatch
:
true
,
frameworks
:
[
"jasmine"
],
browsers
:
[
"Chrome"
,
"Firefox"
],
plugins
:
[
"karma-junit-reporter"
,
"karma-chrome-launcher"
,
"karma-firefox-launcher"
,
"karma-jasmine"
]
});
};
Now do the following to configure Karma as the test framework:
Now we need to add new test specifications for the Chapter 5 project. Do the following:
/* chapter5/controllerSpec.js */
describe
(
'AngularJS Blog Application'
,
function
()
{
beforeEach
(
module
(
'blogApp'
));
describe
(
'BlogCtrl'
,
function
()
{
var
scope
,
ctrl
;
beforeEach
(
inject
(
function
(
$rootScope
,
$controller
)
{
scope
=
$rootScope
.
$new
();
ctrl
=
$controller
(
'BlogCtrl'
,
{
$scope
:
scope
});
}));
it
(
'should create show blog entry count'
,
function
()
{
console
.
log
(
"blogList:"
+
scope
.
blogList
.
length
);
expect
(
scope
.
blogList
.
length
).
toEqual
(
2
);
});
});
describe
(
'BlogViewCtrl'
,
function
()
{
var
scope
,
ctrl
,
$httpBackend
;
beforeEach
(
inject
(
function
(
_$httpBackend_
,
$routeParams
,
$rootScope
,
$controller
)
{
$httpBackend
=
_$httpBackend_
;
$httpBackend
.
expectGET
(
'blogPost'
).
respond
({
_id
:
'1'
});
$routeParams
.
id
=
'1'
;
scope
=
$rootScope
.
$new
();
ctrl
=
$controller
(
'BlogViewCtrl'
,
{
$scope
:
scope
});
}));
it
(
'should show blog entry id'
,
function
()
{
expect
(
scope
.
blogEntry
.
_id
).
toEqual
(
1
);
});
});
});
The new test specification will unit test both controllers. Right-click the project and select “Test” from the menu. Karma will start. You should see both Chrome and Firefox browser windows open. The NetBeans test results window should open and display two passed tests for Chrome and two passed tests for Firefox.
If you get any error messages or failed tests, go back over this section and verify that you completed all the configurations and installations. You can also download the Chapter 5 code from the GitHub project site.
Next, we need to create a Protractor configuration file for the project. Create a new JavaScript file named conf.js under the test folder of the Chapter 5 project. Enter the code shown here in the new file:
/* chapter5/conf.js Protractor configuration file */
exports
.
config
=
{
seleniumAddress
:
'http://localhost:4444/wd/hub'
,
specs
:
[
'e2e/blog-spec.js'
]
};
Now we need to create a Protractor test specification. Do the following:
Then copy the code shown next into the new blog-spec.js file.
Make sure the lines browser.get("http://localhost:8383/AngularJsBlog/");
match the URL that you use on your system to call the blog application. The URL can be different for different development environments and can depend on how you named your project.
/* chapter5/blog-spec.js */
describe
(
"Blog Application Test"
,
function
(){
it
(
"should test the main blog page"
,
function
(){
browser
.
get
(
"http://localhost:8383/AngularJsBlog/"
);
expect
(
browser
.
getTitle
()).
toEqual
(
"AngularJS Blog"
);
//gets the blog list
var
blogList
=
element
.
all
(
by
.
repeater
(
'blogPost in blogList'
));
//tests the size of the blogList
expect
(
blogList
.
count
()).
toEqual
(
2
);
browser
.
get
(
"http://localhost:8383/AngularJsBlog/#!/blogPost/1"
);
expect
(
browser
.
getTitle
()).
toEqual
(
"AngularJS Blog"
);
//gets the comment list
var
commentList
=
element
.
all
(
by
.
repeater
(
'comment in blogEntry.comments'
));
//checks the size of the commentList
expect
(
commentList
.
count
()).
toEqual
(
2
);
});
});
Start a new command window and enter the following command to start the test server:
webdriver-manager start
Open a new command window and navigate to the root of the Chapter 5 project. Type the command:
protractor test/conf.js
You should see a browser window open. You should then see the test script navigate through the pages of the blog application. When the Protractor script has finished, the browser window will close.
You should see results like the following in the command window when the Protractor script completes. The number of seconds that it takes the script to finish will vary depending on your particular system:
Finished in 1.377 seconds 1 test, 4 assertions, 0 failures
In this chapter we built our view using Twitter Bootstrap. We also made our application responsive to different screen sizes using CSS3. We configured both Karma and Protractor for our blog project, and ran both unit and end-to-end tests.
We will now cover REST services and how they are used in AngularJS. Then we will move on to the model.