Node
brew install nvm
export NVM_DIR=~/.nvm
source $(brew --prefix nvm)/nvm.sh
nvm install v4.0.0
nvm use v4.0.0
npm install -g express-generator
This will create a symlink in bin which points to express module in ~/.nvm/versions/v4.0.0/lib/node_modules/ ~/.nvm/bin/express is the symlink created. This is automatically sourced since .nvm/bin is in the path mentioned in .bash_profile or .bashrc dependending on the shell you use
create a empty dir to install express app
mkdir express
install a default express app
express
This will create the folder structure of the app
install express
in the express folder type
npm install
Create empty dir project1
mkdir project1
cd project1
type express --help
express --help
css option stylus
We will use stylus css option so when we create an app using express use
express --css stylus
package.json
package.json has all the dependencies of the project. it is similar to maven
vim package.json
install app using package.json
npm install
npm install will install app using package.json. It will include all depdencies on package.json
launch the application
npm start
localhost 3000
app starts on localhost 3000 do a curl -i (-i is the get response headers). node js and express have an inbuilt server which launches on port 3000 after npm start
curl -i localhost:3000
What does package.json do
package.json has a dependency section
npm install looks at these dependecies and installs them in node_modules. Do not checkin node_modules
stylus files
.styl files are css preprocessors which have code to generate css. node will read these files and generate css files. These files are in the public/stylesheets
routes
routes is a switch board. currently when you start app it will just have the index view
views
views are present in /views folder. It will have a index.jade which extends from layout.jade
app.js
first block is requires. the next instantiates app and next sets config option. app.use is middleware code. Note the app.use("/", "routes") This says routes has the root index, which will render index.js route
Jade is a templating engine processed on server side. It has syntax built on indentation
stylus is a css language. It can assign variables to to constants
eg link:color = #FFFFFF. a{color: link-color} instead of repeating FFFFF all around code (similar to public static String in java)
check style.styl in project created
stacked to horizontal(one of the mostly used features)
we can create a row and in the row can have div with classes .col-mid-1 etc. Search stacked to horizontal in bootstrap site
Bootstrap too comes with less and saas version apart from its css version
static files are served using the public folder in the project. If I create a file named hello.html in public folder it can be accessed as http://localhost:3000/hello.html. Basically public is root for static files
moustache
moustace is tamplating engine which uses curly braces {}. One of the main things in moustache is that it can be used with many languager
Handlebars.js
build only for javascript. it is build over moustache and provides server side and client side templating
to use handlebars put express-handlebars in package.json and install it using npm install, then change your views engine in app.js and then make sure you name views with .handlebars extension
Saas
saas is another preprocessor option built with ruby. with epxress you can use it using express --css compass
less
less is another css preprocessor built with javascript
Passport js
Mongoose js
Karma Test Runner
Mocha js
Chai
Sinon js, supertest
package.json
{
"name": "project1",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"body-parser": "~1.13.2",
"cookie-parser": "~1.3.5",
"debug": "~2.2.0",
"express": "~4.13.1",
"jade": "~1.11.0",
"morgan": "~1.6.1",
"serve-favicon": "~2.3.0",
"stylus": "0.42.3",
"passport": "0.2.*",
"mongoose": "3.8.*"
},
"devDependencies": {
"chai": "1.10.*",
"karma": "0.12.*",
"mocha": "2.0.*",
"sinon": "1.11.*",
"supertest": "0.10.*"
}
}
versioning in node
routes
We will not require the users routes so in app js comment out the following
build a contact route
var express = require('express');
var router = express.Router();
router.get('/',function(req,res){
res.send("it worked");
});
module.exports = router
app.js changes
var contacts = require('./routes/contacts')
app.use('/contacts', contacts);
supervisor
// add supervisor in devdependencies
"devDependencies":{
"supervisor": "*"
}
"scripts": {
"start": "node ./node_modules/.bin/supervisor ./bin/www"
},
create user interface
we will use bootstrap to create nice user interfaces for our application
in order to use bootstrap we need to import it in style.styl file in public/stylesheets folder
put the below 2 lines in "style.styl*
also make sure to download the css version of bootstrap and put it in public/stylesheet folder
your stylesheet folder should now contain
import "bootstrap.min.css"
import "bootstrap.theme.css"
create contacts html for project
create 3 files in views folder
.form-group
label(for="fullname") Full Name
input#fullname.form-control(name="fulname", type="text")
.form-group
label(for="job") Job/position
input#job.form-control(name="jon", type="text")
.form-group
label(for="nickname") nickname
input#nickname.form-control(name="nickname", type="text")
.form-group
label(for="email") E-mail Address
input#email.form-control(name="email", type="text")
extends layout
block content
.row
.col-md-6
h1 Add a contact
form(role="form", method="post", action="")
include editform
button.btn.btn-primary(type="submit") Add user
extends layout
block content
.row
.col-md-6
h1 Add a contact
form(role="form", method="post", action="/contacts/1")
include editform
button.btn.btn-primary(type="submit") Edit user
.col-md-6
h2 Notes
form(roles="form", method="post", action="/contacts/1")
dl
dt Jan 2 2014
dd Prefers italian food
dt Jan 19 2014
dd Just moved into a new office
.form-group
label(for="notes")
textarea#notes.form-control(name="notes")
button.btn.btn-default(type="submit", value="addnote") Add note
** put the new jade templates in contact.js **
var express = require('express');
var router = express.Router();
router.get('/',function(req,res){
res.render("list", {});
});
router.get('/add', function(req,res){
res.render('add', {});
});
router.route('/contact_id')
.all(function(req,res,next){
contact_id = req.params.contact_id;
next();
})
.get(function(req,res){
res.render('edit', {});
})
.post(function(req,res){
res.send('Post for contact '+ contact_id);
})
.put(function(req,res){
res.send('Put for contact '+ contact_id);
})
module.exports = router
extends layout
block content
h1= title
p Welcome to #{title}
p
a.btn.btn-default(href="/contacts/") View Contacts
npm install underscore --save
underscore@1.8.3 node_modules/underscore
--save will install it and automatically add to the package.json as well
now in contact.js add the following line
var _ = require('underscore');
function lookupContact(contact_id){
return _.find(contacts, function(c){
return c_id = parseInt(contact_id);
});
}
function findMaxId() {
return _.max(contacts, function(contact){
return contact.id;
});
}
In contact.js
router.get('/',function(req,res){
res.render("list", {contacts: contacts});
});
In contact.js
router.post('/', function(req,res){
var new_contact_id = findMaxId() + 1;
var new_contact = {
id: new_contact_id,
name: req.body.fullname,
job: req.body.job,
nickname: req.body.nickname,
email: req.body.email
}
contacts.push(new_contact);
res.send('New contact created with id: ' + new_contact.id);
//res.redirect('/contacts/');
});
router.get('/add', function(req,res){
res.render('add', {contact:{}});
});
router.route('/contact_id')
.all(function(req,res,next){
contact_id = req.params.contact_id;
contact = lookupContact(contact_id);
next();
})
.get(function(req,res){
res.render('edit', {contact:contact});
})
.post(function(req,res){
if(!contact.notes){
contact.notes = [];
}
contact.notes.push({
created: Date(),
note: req.body.notes
});
res.send('Created new note for contact id '+ contact_id);
//res.redirect('/contact'+contact_id);
})
put(function(req,res){
contact.name = req.body.fullname;
contact.job = req.body.job;
contact.nickname = req.body.nickname;
contact.email = req.body.email
res.send('Update succeeded for contact id '+ contact_id);
//res.redirect('/contacts/');
})
extend layout
block content
h1 Your contacts
p Here is the list of your contacts
p
a#delete.btn.btn-default(href="#") Delete
|
a#add.btn.btn-default(href="/contacts/add") Add new
table.table
thead
tr
th
th Name
th Nickname
th Email
tbody
tr
td
input(type="checkbox", id="1")
td
a(href="/contacts/1") Joe Smith
| Plumber
td Joe
td
a(href="mailto:joe@gmail.com") joe@gmail.com
tr
td
input(type="checkbox", id="2")
td
a(href="/contacts/2") pratik kale
| Carpenter
td Joe
td
a(href="mailto:joe@gmail.com") pratikkale@gmail.com
tr
td
input(type="checkbox", id="3")
td
a(href="/contacts/3") litesh sajnani
| engineer
td Joe
td
a(href="mailto:joe@gmail.com") liteshsajnani@gmail.com
extend layout
block content
h1 Your contacts
p Here is the list of your contacts
p
a#delete.btn.btn-default(href="#") Delete
|
a#add.btn.btn-default(href="/contacts/add") Add new
table.table
thead
tr
th
th Name
th Nickname
th Email
tbody
if !contacts.length
tr
td(colspan=4) You should add a contact
else
each contact in contacts
tr
td
input(type="checkbox", id =contact.id)
td
a(href="/contacts/#{contact.id}") #{contact.name}
| #{contact.job}
td #{contact.nickname}
td
a(href="mailto:#{contact.email}") #{contact.email}
** Full stack testing **
"test":"./node_modules/.bin/mocha -u tdd"
"scripts": {
"start": "node ./node_modules/.bin/supervisor node ./bin/www",
"test": "./node_modules/.bin/mocha -u tdd"
},
** First Test **
var chai = require('chai');
var assert = chai.assert;
//test are grouped into suite using describe function
//typically we put suite into a file as same name of module it loads
//so typically we will have 1 describe for a file
//we cannot have a describe inside describe
describe('First test suite', function(){
x = 0;
it('Should pass', function() {
assert.equal(1,x);
});
});
var chai = require('chai');
var assert = chai.assert;
beforeEach(function(){
x = x+1
})
describe('First test suite', function(){
x = 0;
it('Should pass', function() {
assert.equal(1,x);
});
});
var chai = require('chai');
var assert = chai.assert;
beforeEach(function(){
x = x+1
})
describe('First test suite', function(){
x = 0;
it('Should pass', function() {
assert.equal(1,x);
});
it('Should also pass', function(){
assert.equal(1,x);
});
});
var chai = require('chai');
var assert = chai.assert;
beforeEach(function(){
x = x+1
});
afterEach(function(){
x = 0;
});
describe('First test suite', function(){
x = 0;
it('Should pass', function() {
assert.equal(1,x);
});
it('Should also pass', function(){
assert.equal(1,x);
});
});
** Testing some real code: test-Jade**
var chai = require('chai');
var assert = chai.assert;
var jade = require('jade');
beforeEach(function(){
x = x+1
});
afterEach(function(){
x = 0;
});
describe('First test suite', function(){
x = 0;
it('Should pass', function() {
assert.equal(1,x);
});
it('Should also pass', function(){
assert.equal(1,x);
});
it('Jade test', function(){
var template = "#container hi";
var expected = '<div id = "container"></div>';
var result = jade.render(template);
assert.equal(expected,result);
});
});
** Testing http requests **
** Test contact and expect 200 ok **
var chai = require('chai');
var assert = chai.assert;
var jade = require('jade');
var request = require('supertest');
var app = require('../app');
beforeEach(function(){
x = x+1
});
afterEach(function(){
x = 0;
});
describe('First test suite', function(){
x = 0;
it('Should pass', function() {
assert.equal(1,x);
});
it('Should also pass', function(){
assert.equal(1,x);
});
it('Jade test', function(){
var template = "#container";
var expected = '<div id = "container"></div>';
var result = jade.render(template);
assert.equal(expected,result);
});
it('Supertest test', function(done){
request(app).get('/contacts')
.expect(200,done);
});
});
** note done above us used for asyn testing **
** expect expects a 200 when stuff is done **
./node_modules/karma/bin
./node_modules/karma/bin/karma init
public/javascripts/**/*.js
browser-tests/**/*.js
"scripts": {
"start": "node ./node_modules/.bin/supervisor node ./bin/www",
"test": "./node_modules/.bin/mocha -u tdd"
"karma": "./node_modules/karma/bin/karma start --single-run"
},