prev-radius | average | radius | count |
---|---|---|---|
0 | 25 | 50.1 | 1 |
50.1 |
package.json
{
"name": "Mean_PC",
"namelower": "mean_pc",
"version": "0.0.1",
"description": "An example AngularJS project",
"readme": "README.md",
"repository": {
"type": "git",
"url": "git@v9c:mean_pc.git"
},
"dependencies": {
"angular": "^1.4",
"bootstrap": "^3.3.5",
"ui.router": "^0.2.15"
},
"devDependencies": {
"browser-sync": "^2.7.13",
"gulp": "^3.8.8",
"gulp-notify": "^2.2.0",
},
"scripts": {
"postinstall": "bower install"
}
}
var gulp = require('gulp');
gulp.task('default', function() {
// place code for your default task here
});
npm install && bower install && gulp watch
When you change a file, it is automatically reloaded in all open browsers. You may be building a site for both mobile and desktop, so you might have two browsers open, anything you do in one will automatically be done in another. Very cool.
package.json
"devDependencies": { "browser-sync": "^2.0" }
gulpfile.js
Send notifications to notify-send
on linux, so you get popup
messages when errors, etc… occur.
package.json
"devDependencies": { "gulp-notify": "^2.2.0" }
gulpfile.js
– app
– index.html | |
– scripts | |
– app.coffee | |
– controllers | |
`– login.coffee | |
`– services | |
`– service.coffee |
`– views
– user_home.html |
`– login.html
Say we use the URL: http://0.0.0.0:9000/#/anon/login
First we check/setup routing in:
app/scripts/app.coffee
Here we find:
angular
.config(...) ->
$stateProvider
.state 'anon.login', {
url: '/login',
templateUrl: 'views/login.html',
controller: 'LoginCtrl' }
This means, when we are in state: ‘anon’ (i’ll explain that more later), and access the url:
anon/login
we first run the
LoginCtrl
Controller, we find this is defined in:
app/scripts/controllers/login.coffee
which has the following code:
next_state = 'user'
$scope.login = ->
Principal.authenticate $scope.user.email, $scope.user.password, next_state, $scope.user.rememberme
$scope.princ = Principal
Here we define the function login
, which presumably we’ll use in the
template. Looking at the template, app/views/login.html
we get:
<form name="loginForm"
ng-submit="login()">
We see that when the form is submitted it executes the login()
function we added to the scope. This in turn calls the
Principal.authenticate()
method. The Principal
service is defined
in: app/scripts/services/service.coffee
:
authenticate: (email, password, next_state, rememberme) ->
Login.save {
'email': email,
'password': password }, (resp) ->
$log.debug(resp)
# TODO:
# here we can check for success/failure in the json returned from the server
# { status: "success", "fail", "error"
# data: { token: "abc123" }
# }
if resp.token
_login(resp.token, email, next_state, rememberme)
else
_logout()
$log.error "Unsuccessful authentication"
This calls the Login.save
method, which is define in the same file
like so:
.factory 'Login', [ '$resource', 'BACKENDURL', ($resource, BACKENDURL) ->
login_uri = BACKENDURL + "/login"
$resource login_uri
]
BACKENDURL
is a constant defined on the angular app in app.coffee
angular.constant("BACKENDURL", "http://localhost:5000/famtree/api/v1.0")
This just basically identifies the backend url of:
http://localhost:5000/famtree/api/v1.0/login
The Login.save()
method takes hash to POST
to the url, in our
case:
{
'email': email,
'password': password
}
The second arg: (resp)
is the response to the POST
. Since we are
returning a JSON object this response will be nothing more than a
javascript object, with members being the JSON variables sent back.
"data": {
"token": "bgP ... $-Q"
},
"status": "success"
finally we check for the existence of the token
, and if found call
the _login
function.
if resp.token
_login(resp.token, email, next_state, rememberme)
which is defined as:
_login = (token, email, next_state, rememberme) ->
_identity = token
_authenticated = true
_email = email
if rememberme
_persist()
$state.go next_state
We set properties: identity, authenticated, and email of the
Principal
service/(object).
If the rememberme
flag is passed, we persist the token to the
clients local storage:
_persist = ->
user_info =
'identity': _identity,
'email': _email
localStorageService.set 'user_info', user_info
Finally, we tell the app to go to the next state, which is user
.
Going back to
app/scripts/app.coffee
we’ve defined this like so:
.state 'user', {
url: '/user',
templateUrl: 'views/user_home.html',
controller: 'MainCtrl' }
So we change the url to: /user
, run the MainCtrl
controller, and
go to the app/views/user_home.html
template.
Reference tutorial, building the phone catalog app:
https://docs.angularjs.org/tutorial
Beginner tutorial
http://campus.codeschool.com/courses/shaping-up-with-angular-js/intro
Create an empty project folder, and add two files: index.html
and
app.js
.
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="myApp" ng-controller="MyCtrl">
<div>
{{test}}
</div>
</body>
</html>
var app = angular.module('myApp', []);
app.controller('MyCtrl', [
'$scope',
function($scope){
$scope.test = 'Hello world!';
}]);
Now run the simple http-server
and navigate to:
http://127.0.0.1:8080/index.html
NOTE: if you haven’t got http-server
installed you can do so with:
sudo npm install -g http-server
in file: app/index.html
<script src="bower_components/angular/angular.js">
Go to your front end project folder and do
yo angular --coffee
Creates a web app configured for the angular framework and uses coffee script instead of Javascript and Sass/Scss instead of CSS.
list dependencies in file: bower.json
In app.js
file:
var app = angular.module('gemStore',[]);
here the second param, the empty list [], means there are no dependencies.
<html ng-app="gemStore">
<body>
<script src="angular.min.js"></script>
<script src="app.js"></script>
</body>
</html>
{{ "Hello World!" }}
in *.js:
app.controller('StoreController', function() {
});
in *.js:
app.controller('StoreController', function() {
this.product = gem;
});
var gem = {
name = "Ruby",
price = 3.4
}
<div ng-controller="StoreController as store">
Name: {{ store.product.name }}<br/>
Price: {{ store.product.price }}
</div>
in *.js
app.controller('StoreController', function() {
this.product = gem;
});
var gem = {
name = "Ruby",
price = 3.4,
canPurchase = false
}
in *.html
<button ng-show="store.product.canPurchase">Add to Cart</button>
Adding a param: soldOut
var gem = {
name = "Ruby",
price = 3.4,
canPurchase = false,
soldOut = true
}
<div ng-hide="store.product.soldOut">
Name: {{ store.product.name }}
</div>
var gems = [
{
name = "Ruby",
price = 3.4,
canPurchase = false,
soldOut = true
}
<div ng-repeat="product in store.products">
Name: {{ product.name }}<br/>
Price: {{ product.price }}
</div>
Price: {{ price | currency }}
{{ data | filter:options }}
{{ '12312312312' | date:'MM/dd/yyyy @ h:mma'}} -> 12/27/2014 @ 12:50AM
{{ 'fenton' | uppercase }}
{{ 'Wonderful World' | limitTo:8 }}
<li ng-repeat='production in store.products | orderBy:'-price'">
var images = [{ thumb: 'ruby.thumb.gif',
full: 'ruby.gif' },
{ thumb: 'diamond.thumb.gif',
full: 'diamond.gif' }]
app.controller('StoreController', function () {
this.images = images;
});
Use it:
<img ng-src="{{ store.images[0].full }}"/>
<li><a href ng-click="tab = 1">Description</a></li>
{{ tab }}
When link is clicked attribute tab
is set to value 1
Set the class to active
, if:
tab === 1
<li ng-class="{ active:tab === 1 }">
<a href ng-click="tab = 1">Description</a>
</li>
<section ng-init="tab = 1">
<ul class="nav nav-pills">
<li ng-class="{ active:tab === 1 }"> <a href ng-click="tab = 1">Description</a></li>
<li ng-class="{ active:tab === 2 }"> <a href ng-click="tab = 2">Specification</a></li>
<li ng-class="{ active:tab === 3 }"> <a href ng-click="tab = 3">Reviews</a></li>
</ul>
</section>
<div class="panel" ng-show="tab === 1">
<h4>Description</h4>
<p>{{product.description}}</p>
</div>
<div class="panel" ng-show="tab === 2">
<h4>Specification</h4>
<p>{{product.description}}</p>
</div>
<div class="panel" ng-show="tab === 3">
<h4>Reviews</h4>
<p>{{product.description}}</p>
</div>
app.controller('PanelController', function () {
this.tab = 1;
this.selectTab = function(setTab) {
this.tab = setTab
};
this.isSelected = function(checkTab) {
return this.tab === checkTab
};
binding data:
<select ng-model="review.stars">
<option value='1'>1 star</option>
<option value='2'>2 stars</option>
</select>
<input type="checkbox" ng-model="review.terms"/>I agree.
Favorite Color:
<input type="radio" ng-model="review.color" value="blue"/>Blue
<input type="radio" ng-model="review.color" value="red"/>Red
<form name="reviewForm"
ng-controller="ReviewController as reviewCtrl"
ng-submit="reviewCtrl.addReview(product)">
associated js function:
app.controller('ReviewController', function() {
this.review = {};
this.addReview = function(product) {
product.reviews.push(this.review);
this.review = {}
};
Turn off default validation:
<form name="reviewForm"
ng-controller="ReviewController as reviewCtrl"
ng-submit="reviewCtrl.addReview(product)"
novalidate>
<!-- input elements here -->
<input type="submit" id="submit" value="Submit" />
</form>
Indicate required fields
<select ng-model="review.stars" required>
Show validity
<div> Review Form is {{reviewForm.$valid}}</div>
Prevent form submission if form is invalid:
ng-submit="reviewForm.$valid && reviewCtrl.addReview(product)"
Indicate to user field is valid or not:
class | meaning |
---|---|
ng-pristine | nothing typed yet |
ng-invalid | not valid yet |
ng-valid | valid |
ng-dirty | something typed |
.ng-invalid.ng-dirty {
/* red border for invalid */
border-color: #FA787E;
}
.ng-valid.ng-dirty {
/* green border for valid */
border-color: #78FA89;
}
Built in validations for:
<input type="email" name="email">
<input type="url" name="homepage">
<input type="number" name="age" min="0" max="110">
in file product-title.html
Name: {{ product.name }}<br/>
Price: {{ product.price | currency }}<br/>
in index.html
<h3 ng-include=“‘product-title.html’”></h3>
index.html
<product-title></product-title>
Dash in HTML corresponds to CamelCase in javascript
app.js
app.directive('productTitle', function() {
return {
restrict: 'E', // E for element
templateUrl: 'product-title.html'
};
});
Can be an Element or Attribute directive. Use Element for UI widgets, and use Attributes for mixin behaviours like: tool-tips.
Element | Attribute |
---|---|
<product-title></product-title> | <h3 product-title></h3> |
Replace the old tag with the template, otherwise just the ‘inner html’ will be replaced, leaving the old tag surrounding the template.
Let user specify some stuff that will go into directive template.
<my-directive>
<b>Hello World!</b>
</my-directive>
.directive 'myDirective', ->
restrict: 'E',
replace: true,
transclude: true,
template: '<h1><ng-transclude></ng-transclude></h1>'
result:
<h1>
<b>Hello World!</b>
</h1>
- true
scope
can be true
, or {}
. If true
then it will get a new
scope that inherits scope from parent, but scope changed here wont go
into the parent (usually the controller) scope.
- {}
If set to {}
, then we DONT inherit scope at all, we have an
isolated scope.
”@” | Text binding / one-way binding |
”=” | Direct model binding / two-way binding |
“&” | Behaviour binding / Method binding |
<my-directive ng-contoller="MyController as myCtrl"></my-directive>
use controller in my-directive.html
<div ng-hide="myCtrl.soldOut">
...
</div>
Move controller inside directive, app.js
Create another *.js file
Have it create it’s own angular module.
In the first module, add the broken out module into the dependencies array
products.js
var app = angular.module('store-products',[]);
app.js
var app = angular.module('gemStore',['store-products']);
Include the file in index.html
<script src="products.js"></script>
angular.module( 'familyTreeService', [])
.factory 'Principal', [ ->
print1: ->
"1"
print2: ->
"2" ]
Now we can use: Principal.print1()
which will return the string
“1”.
Here we are returning an Object literal, that has two properties that are functions.
Get JSON from a URL
$http.get('/products.json', { apiKey: 'MyKey' });
Controllers can use a service like so:
app.controller('MyController', ['$http', function($http) { }]);
More than one service:
app.controller('MyController', ['$http', '$log', function($http, $log) { }]);
Put in an example with success
callback:
app.controller('MyController', ['$http', function($http) {
var store = this;
store.products = [ ];
$http.get('/products.json').success( function(data) {
store.products = data;
});
}]);
$http.post( '/update.json', { param: 'value' });
The RESTful functionality is provided by Angular in the ngResource module.
update bower.json
dependencies:
"dependencies": {
...
"angular-resource": "~1.3.0"
}
fetch dependencies
npm install
inspect app/bower_components
to see dependencies.
https://docs.angularjs.org/api/ngResource/service/$resource
in app/js/services.js
var phonecatServices = angular.module('phonecatServices', ['ngResource']);
phonecatServices.factory('Phone', ['$resource',
function($resource){
return $resource('phones/:phoneId.json', {}, {
query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
});
}]);
Add the dependency:
angular.module('phonecatApp', ['ngRoute', 'phonecatControllers','phonecatFilters', 'phonecatServices']).
First we create a new module, houseServices
. Then to this we use a
factory method to create a service called House
.
app/scripts/services/services.coffee
houseServices = angular
.module('houseServices', ['ngResource']);
houseServices
.factory('House', ['$resource',
($resource) ->
return $resource('http://0.0.0.0:6543/test_json', {}, {
query: {method:'GET', params:{}, isArray:false}
})
])
The JSON that /test_json
returns is:
{"data":
[ {"age": 23, "name": "fenton"},
{"age": 25, "name": "joe"} ]}
Next we need to add this module dependency into our application.
app/scripts/app.coffee
angular
.module(
'houseApp', [
'ngResource',
'houseServices'
])
We make sure to include the coffee/js file in app/index.html
<script src="scripts/services/services.js"></script>
Then we inject this service into the controller we want to use it in.
app/scripts/controllers/main.coffee
angular.module('houseApp')
.controller 'MainCtrl', ($scope, House) ->
$scope.people = House.query()
Then we use the data in
app/views/main.html
people
<ul>
<li ng-repeat="person in people">
Name: {{ person.name }}<br/>
Age: {{ person.age }}
</li>
</ul>
See your list of people at: http://localhost:9000/
app/scripts/services/services.coffee
healthServices = angular
.module('healthServices', ['ngResource']);
healthServices
.factory('User', ['$resource',
($resource) ->
return $resource('http://localhost:5000/health/api/v1.0/users', {}, {
query: {method:'GET', params:{}, isArray:false}
})
])
app/scripts/controllers/main.coffee
'use strict'
angular.module('healthApp')
.controller 'MainCtrl', ($scope, User) ->
$scope.data = User.query()
json data
{
"json_list": [
{
"email": "[email protected]",
"id": "http://localhost:5000/health/api/v1.0/users/1",
"username": "admin"
},
{
"email": "[email protected]",
"id": "http://localhost:5000/health/api/v1.0/users/2",
"username": "Freddy Fun"
}
]
}
app/views/main.html
people
<ul>
<li ng-repeat="person in data.json_list">
Name: {{ person.username }}<br/>
Email: {{ person.email }}
</li>
</ul>
app/index.html
<script src="scripts/services/services.js"></script>
app/scripts/app.coffee
angular
.module('healthApp', [
'ngRoute',
'ngResource',
'healthServices'
])
see commit: d49ce6b on project: health_fe
AND
commit: ea5c8e3 project: health_be
url = "http://localhost:5000/fam_tree/api/v1.0/login"
angular
.module('famtreeServices', ['ngResource']);
.factory('Login', ['$resource',
($resource) ->
return $resource url, {}, {}
])
Actually there is basically nothing in the service, except for naming
it Login
and the url endpoint.
In the HTML you create a model with your fields like so:
<label for="">Name</label> <input ng-model="addUser.username"> <br/>
<label for="">Email</label> <input ng-model="addUser.email"> <br/>
<button ng-click="submit()">Submit Form</button>
angular.module('healthApp')
.controller 'UserCtrl', ($scope, User) ->
$scope.submit = ->
u1 = new User()
u1.username = $scope.addUser.username
u1.email = $scope.addUser.email
User.save(u1, (data) -> )
Here we inject the User
service. We simply create a new User()
and set whatever properties we want to send across in the post.
Calling User.save(u1, (data) -> )
posts the info in u1
, and the
second arg (data)
is the success callback.
Nothing special here, just add your dependency on ngResource
, and
wire your UserCtrl
into your view.
angular
.module('healthApp', [
'ngRoute',
'ngResource',
'healthServices'
])
.config ($routeProvider) ->
$routeProvider
.when '/',
templateUrl: 'views/main.html'
controller: 'UserCtrl'
$http has an array of $httpProvider.interceptors
. They are just
regular factory services.
module.factory 'myInterceptor', ['$log', ($log) ->
myInterceptor = () ->
$log "see we injected the $log, like a normal service" ]
we register at config time:
module.config ['$httpProvider', ($httpProvider) ->
$httpProvider.interceptors.push 'myInterceptor']
bower.json
"angular-animate": "~1.3.0"
This is the layout template:
app/index.html
<div ng-view></div>
Here is the content that goes in the layout template
app/partials/test.html
put some html here
app/js/app.js
var myApp = angular.module('myApp', ['ngRoute', 'myControllers']);
myApp.config([
'$routeProvider',
function($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: 'PhoneListCtrl'
}).
when('/phones/:phoneId', {
templateUrl: 'partials/phone-detail.html',
controller: 'PhoneDetailCtrl'
}).
otherwise({
redirectTo: '/phones'
});
}]);
We extract URL params from $routeParams
app/js/controllers.js
phonecatControllers.controller(
'PhoneDetailCtrl',
['$scope', '$routeParams',
function($scope, $routeParams) {
$scope.phoneId = $routeParams.phoneId;
}]);
Assume we have a restful source of data, say accessible like:
% curl http://localhost:3000/products
[{"_id":"55962164cca62d070e5db9af",
"short_description":"Kensignton32GBUSB3.0Thumbdrive",
"price":500,
"__v":0}]
app/scripts/services.coffee
angular
.module('healthServices', ['ngResource'])
.factory('Procedure', ['$resource',
($resource) ->
uri = "http://localhost:5000/health/api/v1.0/procedures"
return $resource(uri + '/:id', {id: '@id'}, {})
])
in our controller we populate a list with those values:
app/scripts/controllers/main.coffee
angular.module('healthApp')
.controller 'ClinicCtrl', ($scope, Clinic, Procedure) ->
$scope.all_procedures = Procedure.query()
in our view we can do a basic sort of type ahead with:
app/view/clinics.html
<h2>Search Procedures</h2>
<label for="">Procedure Name</label>
<input ng-model="procTypeAhead"> <br/>
<ul>
<li ng-repeat="proc in all_procedures | filter:procTypeAhead">
{{proc.name}}
</ul>
Now what we type into the procTypeAhead
model input will be used to
filter the list shown in: proc in all_procedures
.
Now it would be better to hide results if nothing is entered and to have a simple instructional placeholder
placeholder:
<input ng-model="procTypeAhead"
placeholder="Enter a procedure such as 'hip replacement'">
Now lets hide results when nothing is typed into search box
We wrap in a <div>
, that hides when ther
<div ng-hide="!procTypeAhead.length">
<ul>
<li ng-repeat="proc in all_procedures | filter:procTypeAhead">
{{$index}} {{proc.name}}
</ul>
</div>
use: limitTo:3
or any other number besides 3
<li ng-repeat="proc in all_procedures | filter:procTypeAhead | limitTo:3">
Go to project directory, clone latest and do
grunt build
this puts website into the dist
folder.
serve with nginx
[program:sh]
user=fenton
autorestart=true
# /home/fenton/projects/pyr1/scripts/prod_deamon_start.sh --port 1050 --user fenton --virtualenv pyr --projdir /home/fenton/projects/python/pyr1
command=/usr/bin/pidproxy /home/fenton/projects/python/pyr1/pserve_50%(process_num)02d.pid /home/fenton/projects/python/pyr1/pyr1/scripts/prod_deamon_start.sh --port 50%(process_num)02d --virtualenv pyr --projdir /home/fenton/projects/python/pyr1 --user fenton
process_name=%(program_name)s-%(process_num)01d
numprocs=1
numprocs_start=0
redirect_stderr=true
stdout_logfile=/home/fenton/projects/python/pyr1/%(program_name)s-%(process_num)01d.log
index.html
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js"></script>
app.js
angular.module('myApp', ['ui.router'])
app.js
app.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: '/home.html',
controller: 'MainCtrl'
});
$urlRouterProvider.otherwise('home');
}]);
put this at the bottom, just before the closing </body>
tag:
index.html
<script type="text/ng-template" id="/home.html">
<div class="page-header">
<h1>My Cool App</h1>
</div>
<!-- rest of template -->
</script>
You need to put the <ui-view>
tag where you want your inline
templates to appear in your page.
:index.html
<body ng-app="flapperNews">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<ui-view></ui-view>
</div>
</div>
Conditionally show stuff in web site if authenticated, or have a given role:
https://gist.github.com/bvaughn/90343c06467e9bcb8d27
$stateProvider.state('authenticated.someState', {
url: '/some-url',
templateUrl: 'views/some-state-view.html',
controller: 'SomeStateController',
permission: 'admin'
});
UI Router allows your states to define a resolves object which specifies dependencies that must be loaded before your state can be entered.
So in a parent, of the above, state = ‘authenticated’,
resolve: {
currentUser: function(Session) {
return Session.isAuthenticated();
}
}
bower install angular-messages --save
Add a <script> to your index.html:
<script src="/bower_components/angular-messages/angular-messages.js"></script>
Then add ngMessages as a dependency for your app:
angular.module('myApp', ['ngMessages']);
Say we have a login form and the backend determines that you have
supplied the incorrect password. In angular we would have a page that
gets routed to from the app.coffee
with:
url: '/login',
templateUrl: 'views/login.html',
controller: 'LoginCtrl' }
in login.html
our form has:
<form ng-submit="login()"
which is defined in the controller LoginCtrl
, found in file:
app/scripts/controllers/login.coffee
which has:
.controller 'LoginCtrl', [
'$scope', 'Principal', '$state', ($scope, Principal, $state) ->
next_state = 'user'
$scope.login = ->
Principal.authenticate $scope, next_state
Here we inject the Principal
service, and call authenticate on it.
Defined in file: app/scripts/services/service.coffee
, it looks like:
authenticate: (form_scope, next_state) ->
# First extract data from scope we need
email = form_scope.user.email
password = form_scope.user.password
rememberme = form_scope.user.rememberme
# Now call the login service
Login.save {
'email': email,
'password': password }, (resp) ->
$log.debug(resp)
# { "status": "success",
# "data": { "token": "bgP ... $-Q" }}
data = resp.data
if resp.status == "success" and data.token
_login(data.token, email, next_state, rememberme)
# { "status": "fail",
# "data": {
# "field": "password"
# "message": "Incorrect Password" }}
if resp.status == "fail"
if data.field == "password"
form_scope.user.password.$invalid = true
error_msg = data.message
form_scope.user.password.error_msg = error_msg
# need to extract failure message
# determine the bad data fields, and their associated message
# then pass this to the angular validation framework so those fields
# are highlighted in form
else
_logout()
$log.error "Unsuccessful authentication"
Testacular/karma = test runner Mocha = test suite chai = assertions
When setting up protractor with yoeman scaffolded app follow:
npm install protractor grunt-protractor-runner --save-dev
test/protractor.conf.js
// seleniumAddress: 'http://localhost:4444/wd/hub',
specs: [
'e2e/*.js', 'test/e2e/*_test.js'
],
capabilities: {
'browserName': 'chrome'
},
baseUrl: 'http://localhost:9000/',
chromeOnly: true,
Gruntfile.js
dont forget comma after preceding item
},
protractor: {
options: {
keepAlive: true,
configFile: "test/protractor.conf.js"
},
run: {}
}
I think the rest you can follow the stack overflow answer for, however run it with:
grunt protractor
if u just want to run the e2e tests.
Protractor is used to run end to end (e2e) tests.
- test files location:
test/e2e
Since e2e interacts with our application as a user would, we need to start the application first:
npm start
Now perform the e2e tests:
npm run protractor
e2e testing is good if you change HTML, or just want to verify the whole app works. Do before committing.
describe('PhoneCat App', function() {
it('should redirect index.html to index.html#/phones', function() {
browser.get('app/index.html');
browser.getLocationAbsUrl().then(function(url) {
expect(url.split('#')[1]).toBe('/phones');
});
});
describe('Phone detail view', function() {
beforeEach(function() {
browser.get('app/index.html#/phones/nexus-s');
});
it('should display placeholder page with phoneId', function() {
expect(element(by.binding('phoneId')).getText()).toBe('nexus-s');
});
});
Install mocha and chai:
sudo npm install -g mocha sudo npm install -g chai
mocha –compilers coffee:coffee-script/register
sudo npm install -g karma-cli npm install karma-sinon --save-dev npm install karma-chai --save-dev npm install karma-mocha --save-dev
Karma is used for unit testing.
- test files location:
test/unit
- Launch unit tests
karma start
runs Karma unit tests and watches the test folder…you can therefore leave running for instant feedback.
Install the karma-cli ‘command line interface’ globally
npm install -g karma-cli
Make a project dir
mkdir karma3 cd karma3
npm init it
npm init
Install tools we’ll be using
npm install --save-dev karma karma-mocha karma-chai karma-phantomjs-launcher
Create a basic karma.conf.js
config file
karma init
see: http://blog.seanclayton.me/installing-node-js-on-arch-linux/