Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ember.js and Jasmine BDD. Building TodoMVC proj...

Stas Sușcov
October 20, 2012

Ember.js and Jasmine BDD. Building TodoMVC project.

My slides from GeekMeet #12 meetup in Cluj-Napoca.
http://geekmeet.ro

Get the code on github:
https://github.com/stas/emberjs-jasmine-slides-geekmeet

Stas Sușcov

October 20, 2012
Tweet

More Decks by Stas Sușcov

Other Decks in Programming

Transcript

  1. Ember.js and Jasmine BDD. Building TodoMVC project. Stas Sușcov ([email protected])

    GeekMeet #12, Cluj-Napoca, Transilvania Octomber 20th, 2012 GeekMeet #12, Cluj-Napoca, Transilvania 1 / 19 Octomber 20th, 2012
  2. About Stas a nerd picky developer interests: web/operations I do

    not do front-end or design I rewrote and maintain TodoMVC Ember.js ports (Œ(food wine cycling)) GeekMeet #12, Cluj-Napoca, Transilvania 2 / 19 Octomber 20th, 2012
  3. About Stas a nerd picky developer interests: web/operations I do

    not do front-end or design I rewrote and maintain TodoMVC Ember.js ports (Œ(food wine cycling)) GeekMeet #12, Cluj-Napoca, Transilvania 2 / 19 Octomber 20th, 2012
  4. About Stas a nerd picky developer interests: web/operations I do

    not do front-end or design I rewrote and maintain TodoMVC Ember.js ports (Œ(food wine cycling)) GeekMeet #12, Cluj-Napoca, Transilvania 2 / 19 Octomber 20th, 2012
  5. About Stas a nerd picky developer interests: web/operations I do

    not do front-end or design I rewrote and maintain TodoMVC Ember.js ports (Œ(food wine cycling)) GeekMeet #12, Cluj-Napoca, Transilvania 2 / 19 Octomber 20th, 2012
  6. About Stas a nerd picky developer interests: web/operations I do

    not do front-end or design I rewrote and maintain TodoMVC Ember.js ports (Œ(food wine cycling)) GeekMeet #12, Cluj-Napoca, Transilvania 2 / 19 Octomber 20th, 2012
  7. About Stas a nerd picky developer interests: web/operations I do

    not do front-end or design I rewrote and maintain TodoMVC Ember.js ports (Œ(food wine cycling)) GeekMeet #12, Cluj-Napoca, Transilvania 2 / 19 Octomber 20th, 2012
  8. Saying JavaScript today, I’m not referring to Node.js, CoffeeScript or

    LiveScript! GeekMeet #12, Cluj-Napoca, Transilvania 3 / 19 Octomber 20th, 2012
  9. Our story we (I was hired by Chevah) were looking

    for a front-end solution for non-front-end developers it had to be MVC it had to be something which was around for some time already it had to know fancy stuff like: bindings observers routing little or almost no HTML (declarative views) features over modularity (should not be spread over into a bunch of separate projects) GeekMeet #12, Cluj-Napoca, Transilvania 4 / 19 Octomber 20th, 2012
  10. Our story we (I was hired by Chevah) were looking

    for a front-end solution for non-front-end developers it had to be MVC it had to be something which was around for some time already it had to know fancy stuff like: bindings observers routing little or almost no HTML (declarative views) features over modularity (should not be spread over into a bunch of separate projects) GeekMeet #12, Cluj-Napoca, Transilvania 4 / 19 Octomber 20th, 2012
  11. Our story we (I was hired by Chevah) were looking

    for a front-end solution for non-front-end developers it had to be MVC it had to be something which was around for some time already it had to know fancy stuff like: bindings observers routing little or almost no HTML (declarative views) features over modularity (should not be spread over into a bunch of separate projects) GeekMeet #12, Cluj-Napoca, Transilvania 4 / 19 Octomber 20th, 2012
  12. Our story we (I was hired by Chevah) were looking

    for a front-end solution for non-front-end developers it had to be MVC it had to be something which was around for some time already it had to know fancy stuff like: bindings observers routing little or almost no HTML (declarative views) features over modularity (should not be spread over into a bunch of separate projects) GeekMeet #12, Cluj-Napoca, Transilvania 4 / 19 Octomber 20th, 2012
  13. Our story we (I was hired by Chevah) were looking

    for a front-end solution for non-front-end developers it had to be MVC it had to be something which was around for some time already it had to know fancy stuff like: bindings observers routing little or almost no HTML (declarative views) features over modularity (should not be spread over into a bunch of separate projects) GeekMeet #12, Cluj-Napoca, Transilvania 4 / 19 Octomber 20th, 2012
  14. Our story we (I was hired by Chevah) were looking

    for a front-end solution for non-front-end developers it had to be MVC it had to be something which was around for some time already it had to know fancy stuff like: bindings observers routing little or almost no HTML (declarative views) features over modularity (should not be spread over into a bunch of separate projects) GeekMeet #12, Cluj-Napoca, Transilvania 4 / 19 Octomber 20th, 2012
  15. Our story we (I was hired by Chevah) were looking

    for a front-end solution for non-front-end developers it had to be MVC it had to be something which was around for some time already it had to know fancy stuff like: bindings observers routing little or almost no HTML (declarative views) features over modularity (should not be spread over into a bunch of separate projects) GeekMeet #12, Cluj-Napoca, Transilvania 4 / 19 Octomber 20th, 2012
  16. Our story we (I was hired by Chevah) were looking

    for a front-end solution for non-front-end developers it had to be MVC it had to be something which was around for some time already it had to know fancy stuff like: bindings observers routing little or almost no HTML (declarative views) features over modularity (should not be spread over into a bunch of separate projects) GeekMeet #12, Cluj-Napoca, Transilvania 4 / 19 Octomber 20th, 2012
  17. Our story we (I was hired by Chevah) were looking

    for a front-end solution for non-front-end developers it had to be MVC it had to be something which was around for some time already it had to know fancy stuff like: bindings observers routing little or almost no HTML (declarative views) features over modularity (should not be spread over into a bunch of separate projects) GeekMeet #12, Cluj-Napoca, Transilvania 4 / 19 Octomber 20th, 2012
  18. What’s the story with TodoMVC has the mission to help

    developers understand and pick the best of available JavaScript frameworks mostly MV* projects has a strict list of specs it will also offer tests (WIP) has some nice guys as developers/maintainers Addy Osmani Sindre Sorhus collaborates directly with project authors when it comes to reviews/design awesome educational project http://todomvc.com GeekMeet #12, Cluj-Napoca, Transilvania 5 / 19 Octomber 20th, 2012
  19. What’s the story with TodoMVC has the mission to help

    developers understand and pick the best of available JavaScript frameworks mostly MV* projects has a strict list of specs it will also offer tests (WIP) has some nice guys as developers/maintainers Addy Osmani Sindre Sorhus collaborates directly with project authors when it comes to reviews/design awesome educational project http://todomvc.com GeekMeet #12, Cluj-Napoca, Transilvania 5 / 19 Octomber 20th, 2012
  20. What’s the story with TodoMVC has the mission to help

    developers understand and pick the best of available JavaScript frameworks mostly MV* projects has a strict list of specs it will also offer tests (WIP) has some nice guys as developers/maintainers Addy Osmani Sindre Sorhus collaborates directly with project authors when it comes to reviews/design awesome educational project http://todomvc.com GeekMeet #12, Cluj-Napoca, Transilvania 5 / 19 Octomber 20th, 2012
  21. What’s the story with TodoMVC has the mission to help

    developers understand and pick the best of available JavaScript frameworks mostly MV* projects has a strict list of specs it will also offer tests (WIP) has some nice guys as developers/maintainers Addy Osmani Sindre Sorhus collaborates directly with project authors when it comes to reviews/design awesome educational project http://todomvc.com GeekMeet #12, Cluj-Napoca, Transilvania 5 / 19 Octomber 20th, 2012
  22. What’s the story with TodoMVC has the mission to help

    developers understand and pick the best of available JavaScript frameworks mostly MV* projects has a strict list of specs it will also offer tests (WIP) has some nice guys as developers/maintainers Addy Osmani Sindre Sorhus collaborates directly with project authors when it comes to reviews/design awesome educational project http://todomvc.com GeekMeet #12, Cluj-Napoca, Transilvania 5 / 19 Octomber 20th, 2012
  23. What’s the story with TodoMVC has the mission to help

    developers understand and pick the best of available JavaScript frameworks mostly MV* projects has a strict list of specs it will also offer tests (WIP) has some nice guys as developers/maintainers Addy Osmani Sindre Sorhus collaborates directly with project authors when it comes to reviews/design awesome educational project http://todomvc.com GeekMeet #12, Cluj-Napoca, Transilvania 5 / 19 Octomber 20th, 2012
  24. What’s the story with TodoMVC has the mission to help

    developers understand and pick the best of available JavaScript frameworks mostly MV* projects has a strict list of specs it will also offer tests (WIP) has some nice guys as developers/maintainers Addy Osmani Sindre Sorhus collaborates directly with project authors when it comes to reviews/design awesome educational project http://todomvc.com GeekMeet #12, Cluj-Napoca, Transilvania 5 / 19 Octomber 20th, 2012
  25. What’s the story with TodoMVC has the mission to help

    developers understand and pick the best of available JavaScript frameworks mostly MV* projects has a strict list of specs it will also offer tests (WIP) has some nice guys as developers/maintainers Addy Osmani Sindre Sorhus collaborates directly with project authors when it comes to reviews/design awesome educational project http://todomvc.com GeekMeet #12, Cluj-Napoca, Transilvania 5 / 19 Octomber 20th, 2012
  26. What’s the story with TodoMVC has the mission to help

    developers understand and pick the best of available JavaScript frameworks mostly MV* projects has a strict list of specs it will also offer tests (WIP) has some nice guys as developers/maintainers Addy Osmani Sindre Sorhus collaborates directly with project authors when it comes to reviews/design awesome educational project http://todomvc.com GeekMeet #12, Cluj-Napoca, Transilvania 5 / 19 Octomber 20th, 2012
  27. Why we picked Ember.js because of all you can find

    above º has conventions (cough-cough rails) it is everything you need in one box cause it’s fun to write Ember.js app, and I’ll try to prove it http://emberjs.com GeekMeet #12, Cluj-Napoca, Transilvania 6 / 19 Octomber 20th, 2012
  28. Why we picked Ember.js because of all you can find

    above º has conventions (cough-cough rails) it is everything you need in one box cause it’s fun to write Ember.js app, and I’ll try to prove it http://emberjs.com GeekMeet #12, Cluj-Napoca, Transilvania 6 / 19 Octomber 20th, 2012
  29. Why we picked Ember.js because of all you can find

    above º has conventions (cough-cough rails) it is everything you need in one box cause it’s fun to write Ember.js app, and I’ll try to prove it http://emberjs.com GeekMeet #12, Cluj-Napoca, Transilvania 6 / 19 Octomber 20th, 2012
  30. Why we picked Ember.js because of all you can find

    above º has conventions (cough-cough rails) it is everything you need in one box cause it’s fun to write Ember.js app, and I’ll try to prove it http://emberjs.com GeekMeet #12, Cluj-Napoca, Transilvania 6 / 19 Octomber 20th, 2012
  31. Ember.js Blog app (almost) to be honest, I wrote the

    TodoMVC port while learning Ember.js to make it easier for everyone, I wrote a simple app so you can understand it just by reading my slides your next step will be to check out the code from this repository after what I would like to invite you to take a look at TodoMVC Ember.js port you should try it and maybe send some patches, hints: refactor some tests update the code with upcoming Ember.js v.1.0 API changes rewrite todo.js model GeekMeet #12, Cluj-Napoca, Transilvania 7 / 19 Octomber 20th, 2012
  32. Ember.js Blog app (almost) to be honest, I wrote the

    TodoMVC port while learning Ember.js to make it easier for everyone, I wrote a simple app so you can understand it just by reading my slides your next step will be to check out the code from this repository after what I would like to invite you to take a look at TodoMVC Ember.js port you should try it and maybe send some patches, hints: refactor some tests update the code with upcoming Ember.js v.1.0 API changes rewrite todo.js model GeekMeet #12, Cluj-Napoca, Transilvania 7 / 19 Octomber 20th, 2012
  33. Ember.js Blog app (almost) to be honest, I wrote the

    TodoMVC port while learning Ember.js to make it easier for everyone, I wrote a simple app so you can understand it just by reading my slides your next step will be to check out the code from this repository after what I would like to invite you to take a look at TodoMVC Ember.js port you should try it and maybe send some patches, hints: refactor some tests update the code with upcoming Ember.js v.1.0 API changes rewrite todo.js model GeekMeet #12, Cluj-Napoca, Transilvania 7 / 19 Octomber 20th, 2012
  34. Ember.js Blog app (almost) to be honest, I wrote the

    TodoMVC port while learning Ember.js to make it easier for everyone, I wrote a simple app so you can understand it just by reading my slides your next step will be to check out the code from this repository after what I would like to invite you to take a look at TodoMVC Ember.js port you should try it and maybe send some patches, hints: refactor some tests update the code with upcoming Ember.js v.1.0 API changes rewrite todo.js model GeekMeet #12, Cluj-Napoca, Transilvania 7 / 19 Octomber 20th, 2012
  35. Ember.js Blog app (almost) to be honest, I wrote the

    TodoMVC port while learning Ember.js to make it easier for everyone, I wrote a simple app so you can understand it just by reading my slides your next step will be to check out the code from this repository after what I would like to invite you to take a look at TodoMVC Ember.js port you should try it and maybe send some patches, hints: refactor some tests update the code with upcoming Ember.js v.1.0 API changes rewrite todo.js model GeekMeet #12, Cluj-Napoca, Transilvania 7 / 19 Octomber 20th, 2012
  36. Ember.js Blog app (almost) to be honest, I wrote the

    TodoMVC port while learning Ember.js to make it easier for everyone, I wrote a simple app so you can understand it just by reading my slides your next step will be to check out the code from this repository after what I would like to invite you to take a look at TodoMVC Ember.js port you should try it and maybe send some patches, hints: refactor some tests update the code with upcoming Ember.js v.1.0 API changes rewrite todo.js model GeekMeet #12, Cluj-Napoca, Transilvania 7 / 19 Octomber 20th, 2012
  37. Ember.js Blog app (almost) to be honest, I wrote the

    TodoMVC port while learning Ember.js to make it easier for everyone, I wrote a simple app so you can understand it just by reading my slides your next step will be to check out the code from this repository after what I would like to invite you to take a look at TodoMVC Ember.js port you should try it and maybe send some patches, hints: refactor some tests update the code with upcoming Ember.js v.1.0 API changes rewrite todo.js model GeekMeet #12, Cluj-Napoca, Transilvania 7 / 19 Octomber 20th, 2012
  38. Ember.js Blog app (almost) to be honest, I wrote the

    TodoMVC port while learning Ember.js to make it easier for everyone, I wrote a simple app so you can understand it just by reading my slides your next step will be to check out the code from this repository after what I would like to invite you to take a look at TodoMVC Ember.js port you should try it and maybe send some patches, hints: refactor some tests update the code with upcoming Ember.js v.1.0 API changes rewrite todo.js model GeekMeet #12, Cluj-Napoca, Transilvania 7 / 19 Octomber 20th, 2012
  39. app.js bootstraps our application ApplicationController and ApplicationView are mandatory! rootElement

    is to point the app where it should append views/content connectOutlets uses {{outlet}}, see below 1 var App = Ember.Application.create({ 2 VERSION: ’0.1.0’, 3 rootElement: ’#content’, 4 ApplicationController: Ember.Controller.extend(), 5 ArticleController: Ember.Controller.extend(), 6 ApplicationView: Ember.View.extend({ 7 template: Ember.Handlebars.compile( ’{{outlet}}’ ) 8 }) 9 // The rest of the Models/Controllers/Views 10 // will self append to this namespace 11 }); GeekMeet #12, Cluj-Napoca, Transilvania 8 / 19 Octomber 20th, 2012
  40. app.js bootstraps our application ApplicationController and ApplicationView are mandatory! rootElement

    is to point the app where it should append views/content connectOutlets uses {{outlet}}, see below 1 var App = Ember.Application.create({ 2 VERSION: ’0.1.0’, 3 rootElement: ’#content’, 4 ApplicationController: Ember.Controller.extend(), 5 ArticleController: Ember.Controller.extend(), 6 ApplicationView: Ember.View.extend({ 7 template: Ember.Handlebars.compile( ’{{outlet}}’ ) 8 }) 9 // The rest of the Models/Controllers/Views 10 // will self append to this namespace 11 }); GeekMeet #12, Cluj-Napoca, Transilvania 8 / 19 Octomber 20th, 2012
  41. app.js bootstraps our application ApplicationController and ApplicationView are mandatory! rootElement

    is to point the app where it should append views/content connectOutlets uses {{outlet}}, see below 1 var App = Ember.Application.create({ 2 VERSION: ’0.1.0’, 3 rootElement: ’#content’, 4 ApplicationController: Ember.Controller.extend(), 5 ArticleController: Ember.Controller.extend(), 6 ApplicationView: Ember.View.extend({ 7 template: Ember.Handlebars.compile( ’{{outlet}}’ ) 8 }) 9 // The rest of the Models/Controllers/Views 10 // will self append to this namespace 11 }); GeekMeet #12, Cluj-Napoca, Transilvania 8 / 19 Octomber 20th, 2012
  42. app.js bootstraps our application ApplicationController and ApplicationView are mandatory! rootElement

    is to point the app where it should append views/content connectOutlets uses {{outlet}}, see below 1 var App = Ember.Application.create({ 2 VERSION: ’0.1.0’, 3 rootElement: ’#content’, 4 ApplicationController: Ember.Controller.extend(), 5 ArticleController: Ember.Controller.extend(), 6 ApplicationView: Ember.View.extend({ 7 template: Ember.Handlebars.compile( ’{{outlet}}’ ) 8 }) 9 // The rest of the Models/Controllers/Views 10 // will self append to this namespace 11 }); GeekMeet #12, Cluj-Napoca, Transilvania 8 / 19 Octomber 20th, 2012
  43. app/router.js root route is mandatory and it is where the

    app will route first enter gets called when the route is entered connectOutlets gets called when route controllers/views have to be connected 1 var Router = Ember.Router.extend({ 2 3 root: Ember.Route.extend({ 4 goToPublish: Ember.Route.transitionTo( ’root.publish’ ), 5 6 // GET /#/ 7 index: Ember.Route.extend({ 8 route: ’/’, 9 redirectsTo: ’publish’ 10 }), 11 12 // GET /#/publish 13 publish: Ember.Route.extend({ 14 route: ’/publish’, 15 16 connectOutlets: function( router ) { 17 router.get( ’applicationController’ ).connectOutlet( ’publish’ ); 18 } 19 }), 20 21 // GET /#/article/:id 22 article: Ember.Route.extend({ 23 route: ’/article/:id’, 24 GeekMeet #12, Cluj-Napoca, Transilvania 9 / 19 Octomber 20th, 2012
  44. app/router.js root route is mandatory and it is where the

    app will route first enter gets called when the route is entered connectOutlets gets called when route controllers/views have to be connected 1 var Router = Ember.Router.extend({ 2 3 root: Ember.Route.extend({ 4 goToPublish: Ember.Route.transitionTo( ’root.publish’ ), 5 6 // GET /#/ 7 index: Ember.Route.extend({ 8 route: ’/’, 9 redirectsTo: ’publish’ 10 }), 11 12 // GET /#/publish 13 publish: Ember.Route.extend({ 14 route: ’/publish’, 15 16 connectOutlets: function( router ) { 17 router.get( ’applicationController’ ).connectOutlet( ’publish’ ); 18 } 19 }), 20 21 // GET /#/article/:id 22 article: Ember.Route.extend({ 23 route: ’/article/:id’, 24 GeekMeet #12, Cluj-Napoca, Transilvania 9 / 19 Octomber 20th, 2012
  45. app/router.js root route is mandatory and it is where the

    app will route first enter gets called when the route is entered connectOutlets gets called when route controllers/views have to be connected 1 var Router = Ember.Router.extend({ 2 3 root: Ember.Route.extend({ 4 goToPublish: Ember.Route.transitionTo( ’root.publish’ ), 5 6 // GET /#/ 7 index: Ember.Route.extend({ 8 route: ’/’, 9 redirectsTo: ’publish’ 10 }), 11 12 // GET /#/publish 13 publish: Ember.Route.extend({ 14 route: ’/publish’, 15 16 connectOutlets: function( router ) { 17 router.get( ’applicationController’ ).connectOutlet( ’publish’ ); 18 } 19 }), 20 21 // GET /#/article/:id 22 article: Ember.Route.extend({ 23 route: ’/article/:id’, 24 GeekMeet #12, Cluj-Napoca, Transilvania 9 / 19 Octomber 20th, 2012
  46. app/model/article.js is our model (ActiveRecord class if you want) .property()

    calls define attributes as a computed property it is available for other Ember.js components as well init is the constructor (like new, initialize, construct()) some class methods like: find is part of the conventions and used by router to query a specific model object all is also part of the conventions and used by router to query all available model objects 1 var Article = Ember.Object.extend({ 2 id: null, 3 title: null, 4 content: null, 5 6 // Handle Generation of the slug as a property 7 slug: function() { 8 var slug = this.get( ’title’ ).toLowerCase(); 9 return slug.replace( /\s+?/g, ’-’ ); 10 }.property( ’title’ ).cacheable(), 11 12 // Constructor 13 init: function() { 14 var id = Date.now(); 15 24 Article.reopenClass({ 25 db: {}, 26 27 find: function( id ) { 28 return this.db[ id ]; 29 }, 30 31 all: function() { 32 return this.db; 33 } 34 35 }); GeekMeet #12, Cluj-Napoca, Transilvania 10 / 19 Octomber 20th, 2012
  47. app/model/article.js is our model (ActiveRecord class if you want) .property()

    calls define attributes as a computed property it is available for other Ember.js components as well init is the constructor (like new, initialize, construct()) some class methods like: find is part of the conventions and used by router to query a specific model object all is also part of the conventions and used by router to query all available model objects 1 var Article = Ember.Object.extend({ 2 id: null, 3 title: null, 4 content: null, 5 6 // Handle Generation of the slug as a property 7 slug: function() { 8 var slug = this.get( ’title’ ).toLowerCase(); 9 return slug.replace( /\s+?/g, ’-’ ); 10 }.property( ’title’ ).cacheable(), 11 12 // Constructor 13 init: function() { 14 var id = Date.now(); 15 24 Article.reopenClass({ 25 db: {}, 26 27 find: function( id ) { 28 return this.db[ id ]; 29 }, 30 31 all: function() { 32 return this.db; 33 } 34 35 }); GeekMeet #12, Cluj-Napoca, Transilvania 10 / 19 Octomber 20th, 2012
  48. app/model/article.js is our model (ActiveRecord class if you want) .property()

    calls define attributes as a computed property it is available for other Ember.js components as well init is the constructor (like new, initialize, construct()) some class methods like: find is part of the conventions and used by router to query a specific model object all is also part of the conventions and used by router to query all available model objects 1 var Article = Ember.Object.extend({ 2 id: null, 3 title: null, 4 content: null, 5 6 // Handle Generation of the slug as a property 7 slug: function() { 8 var slug = this.get( ’title’ ).toLowerCase(); 9 return slug.replace( /\s+?/g, ’-’ ); 10 }.property( ’title’ ).cacheable(), 11 12 // Constructor 13 init: function() { 14 var id = Date.now(); 15 24 Article.reopenClass({ 25 db: {}, 26 27 find: function( id ) { 28 return this.db[ id ]; 29 }, 30 31 all: function() { 32 return this.db; 33 } 34 35 }); GeekMeet #12, Cluj-Napoca, Transilvania 10 / 19 Octomber 20th, 2012
  49. app/model/article.js is our model (ActiveRecord class if you want) .property()

    calls define attributes as a computed property it is available for other Ember.js components as well init is the constructor (like new, initialize, construct()) some class methods like: find is part of the conventions and used by router to query a specific model object all is also part of the conventions and used by router to query all available model objects 1 var Article = Ember.Object.extend({ 2 id: null, 3 title: null, 4 content: null, 5 6 // Handle Generation of the slug as a property 7 slug: function() { 8 var slug = this.get( ’title’ ).toLowerCase(); 9 return slug.replace( /\s+?/g, ’-’ ); 10 }.property( ’title’ ).cacheable(), 11 12 // Constructor 13 init: function() { 14 var id = Date.now(); 15 24 Article.reopenClass({ 25 db: {}, 26 27 find: function( id ) { 28 return this.db[ id ]; 29 }, 30 31 all: function() { 32 return this.db; 33 } 34 35 }); GeekMeet #12, Cluj-Napoca, Transilvania 10 / 19 Octomber 20th, 2012
  50. app/model/article.js is our model (ActiveRecord class if you want) .property()

    calls define attributes as a computed property it is available for other Ember.js components as well init is the constructor (like new, initialize, construct()) some class methods like: find is part of the conventions and used by router to query a specific model object all is also part of the conventions and used by router to query all available model objects 1 var Article = Ember.Object.extend({ 2 id: null, 3 title: null, 4 content: null, 5 6 // Handle Generation of the slug as a property 7 slug: function() { 8 var slug = this.get( ’title’ ).toLowerCase(); 9 return slug.replace( /\s+?/g, ’-’ ); 10 }.property( ’title’ ).cacheable(), 11 12 // Constructor 13 init: function() { 14 var id = Date.now(); 15 24 Article.reopenClass({ 25 db: {}, 26 27 find: function( id ) { 28 return this.db[ id ]; 29 }, 30 31 all: function() { 32 return this.db; 33 } 34 35 }); GeekMeet #12, Cluj-Napoca, Transilvania 10 / 19 Octomber 20th, 2012
  51. app/model/article.js is our model (ActiveRecord class if you want) .property()

    calls define attributes as a computed property it is available for other Ember.js components as well init is the constructor (like new, initialize, construct()) some class methods like: find is part of the conventions and used by router to query a specific model object all is also part of the conventions and used by router to query all available model objects 1 var Article = Ember.Object.extend({ 2 id: null, 3 title: null, 4 content: null, 5 6 // Handle Generation of the slug as a property 7 slug: function() { 8 var slug = this.get( ’title’ ).toLowerCase(); 9 return slug.replace( /\s+?/g, ’-’ ); 10 }.property( ’title’ ).cacheable(), 11 12 // Constructor 13 init: function() { 14 var id = Date.now(); 15 24 Article.reopenClass({ 25 db: {}, 26 27 find: function( id ) { 28 return this.db[ id ]; 29 }, 30 31 all: function() { 32 return this.db; 33 } 34 35 }); GeekMeet #12, Cluj-Napoca, Transilvania 10 / 19 Octomber 20th, 2012
  52. app/model/article.js is our model (ActiveRecord class if you want) .property()

    calls define attributes as a computed property it is available for other Ember.js components as well init is the constructor (like new, initialize, construct()) some class methods like: find is part of the conventions and used by router to query a specific model object all is also part of the conventions and used by router to query all available model objects 1 var Article = Ember.Object.extend({ 2 id: null, 3 title: null, 4 content: null, 5 6 // Handle Generation of the slug as a property 7 slug: function() { 8 var slug = this.get( ’title’ ).toLowerCase(); 9 return slug.replace( /\s+?/g, ’-’ ); 10 }.property( ’title’ ).cacheable(), 11 12 // Constructor 13 init: function() { 14 var id = Date.now(); 15 24 Article.reopenClass({ 25 db: {}, 26 27 find: function( id ) { 28 return this.db[ id ]; 29 }, 30 31 all: function() { 32 return this.db; 33 } 34 35 }); GeekMeet #12, Cluj-Napoca, Transilvania 10 / 19 Octomber 20th, 2012
  53. app/controller/publish.js known principle: skinny controllers, fat models controller knows about

    its router and view, use it to handle app logic 1 var PublishController = Ember.Controller.extend({ 2 publish: function() { 3 var article = App.Article.create({ 4 title: this.get( ’parentView.title’ ), 5 content: this.get( ’parentView.content’ ) 6 }); 7 8 this.set( ’parentView.title’, ’’ ); 9 this.set( ’parentView.content’, ’’ ); 10 11 this.get( ’controller.namespace.router’ ).transitionTo( 12 ’article’, article ); 13 }, 14 }); GeekMeet #12, Cluj-Napoca, Transilvania 11 / 19 Octomber 20th, 2012
  54. app/controller/publish.js known principle: skinny controllers, fat models controller knows about

    its router and view, use it to handle app logic 1 var PublishController = Ember.Controller.extend({ 2 publish: function() { 3 var article = App.Article.create({ 4 title: this.get( ’parentView.title’ ), 5 content: this.get( ’parentView.content’ ) 6 }); 7 8 this.set( ’parentView.title’, ’’ ); 9 this.set( ’parentView.content’, ’’ ); 10 11 this.get( ’controller.namespace.router’ ).transitionTo( 12 ’article’, article ); 13 }, 14 }); GeekMeet #12, Cluj-Napoca, Transilvania 11 / 19 Octomber 20th, 2012
  55. app/view/publish.js views can either represent one element view or can

    contain a set of other views see childViews, Ember.TextField, Ember.TextArea, Ember.ContainerView, etc. any attribute ending with Binding, upon instantiation will become a binding to that path it is available for other Ember.js components as well ideally, views will generate your HTML (my opinion) views also handle events, see click, insertNewline, etc. 1 var PublishView = Ember.ContainerView.extend({ 2 childViews: [ ’titleView’, ’contentView’, ’buttonView’ ], 3 titleBinding: ’titleView.value’, 4 contentBinding: ’contentView.value’, 5 6 isEmpty: function() { 7 var empty = false; 8 title = this.get( ’title’ ), 9 content = this.get( ’content’ ); 10 11 if ( title && title.trim() === ’’ && content && content.trim() === ’’ ) { 12 empty = true; 13 } 14 15 return empty; 16 }.property( ’title’, ’content’ ), GeekMeet #12, Cluj-Napoca, Transilvania 12 / 19 Octomber 20th, 2012
  56. app/view/publish.js views can either represent one element view or can

    contain a set of other views see childViews, Ember.TextField, Ember.TextArea, Ember.ContainerView, etc. any attribute ending with Binding, upon instantiation will become a binding to that path it is available for other Ember.js components as well ideally, views will generate your HTML (my opinion) views also handle events, see click, insertNewline, etc. 1 var PublishView = Ember.ContainerView.extend({ 2 childViews: [ ’titleView’, ’contentView’, ’buttonView’ ], 3 titleBinding: ’titleView.value’, 4 contentBinding: ’contentView.value’, 5 6 isEmpty: function() { 7 var empty = false; 8 title = this.get( ’title’ ), 9 content = this.get( ’content’ ); 10 11 if ( title && title.trim() === ’’ && content && content.trim() === ’’ ) { 12 empty = true; 13 } 14 15 return empty; 16 }.property( ’title’, ’content’ ), GeekMeet #12, Cluj-Napoca, Transilvania 12 / 19 Octomber 20th, 2012
  57. app/view/publish.js views can either represent one element view or can

    contain a set of other views see childViews, Ember.TextField, Ember.TextArea, Ember.ContainerView, etc. any attribute ending with Binding, upon instantiation will become a binding to that path it is available for other Ember.js components as well ideally, views will generate your HTML (my opinion) views also handle events, see click, insertNewline, etc. 1 var PublishView = Ember.ContainerView.extend({ 2 childViews: [ ’titleView’, ’contentView’, ’buttonView’ ], 3 titleBinding: ’titleView.value’, 4 contentBinding: ’contentView.value’, 5 6 isEmpty: function() { 7 var empty = false; 8 title = this.get( ’title’ ), 9 content = this.get( ’content’ ); 10 11 if ( title && title.trim() === ’’ && content && content.trim() === ’’ ) { 12 empty = true; 13 } 14 15 return empty; 16 }.property( ’title’, ’content’ ), GeekMeet #12, Cluj-Napoca, Transilvania 12 / 19 Octomber 20th, 2012
  58. app/view/publish.js views can either represent one element view or can

    contain a set of other views see childViews, Ember.TextField, Ember.TextArea, Ember.ContainerView, etc. any attribute ending with Binding, upon instantiation will become a binding to that path it is available for other Ember.js components as well ideally, views will generate your HTML (my opinion) views also handle events, see click, insertNewline, etc. 1 var PublishView = Ember.ContainerView.extend({ 2 childViews: [ ’titleView’, ’contentView’, ’buttonView’ ], 3 titleBinding: ’titleView.value’, 4 contentBinding: ’contentView.value’, 5 6 isEmpty: function() { 7 var empty = false; 8 title = this.get( ’title’ ), 9 content = this.get( ’content’ ); 10 11 if ( title && title.trim() === ’’ && content && content.trim() === ’’ ) { 12 empty = true; 13 } 14 15 return empty; 16 }.property( ’title’, ’content’ ), GeekMeet #12, Cluj-Napoca, Transilvania 12 / 19 Octomber 20th, 2012
  59. app/view/publish.js views can either represent one element view or can

    contain a set of other views see childViews, Ember.TextField, Ember.TextArea, Ember.ContainerView, etc. any attribute ending with Binding, upon instantiation will become a binding to that path it is available for other Ember.js components as well ideally, views will generate your HTML (my opinion) views also handle events, see click, insertNewline, etc. 1 var PublishView = Ember.ContainerView.extend({ 2 childViews: [ ’titleView’, ’contentView’, ’buttonView’ ], 3 titleBinding: ’titleView.value’, 4 contentBinding: ’contentView.value’, 5 6 isEmpty: function() { 7 var empty = false; 8 title = this.get( ’title’ ), 9 content = this.get( ’content’ ); 10 11 if ( title && title.trim() === ’’ && content && content.trim() === ’’ ) { 12 empty = true; 13 } 14 15 return empty; 16 }.property( ’title’, ’content’ ), GeekMeet #12, Cluj-Napoca, Transilvania 12 / 19 Octomber 20th, 2012
  60. app/view/publish.js views can either represent one element view or can

    contain a set of other views see childViews, Ember.TextField, Ember.TextArea, Ember.ContainerView, etc. any attribute ending with Binding, upon instantiation will become a binding to that path it is available for other Ember.js components as well ideally, views will generate your HTML (my opinion) views also handle events, see click, insertNewline, etc. 1 var PublishView = Ember.ContainerView.extend({ 2 childViews: [ ’titleView’, ’contentView’, ’buttonView’ ], 3 titleBinding: ’titleView.value’, 4 contentBinding: ’contentView.value’, 5 6 isEmpty: function() { 7 var empty = false; 8 title = this.get( ’title’ ), 9 content = this.get( ’content’ ); 10 11 if ( title && title.trim() === ’’ && content && content.trim() === ’’ ) { 12 empty = true; 13 } 14 15 return empty; 16 }.property( ’title’, ’content’ ), GeekMeet #12, Cluj-Napoca, Transilvania 12 / 19 Octomber 20th, 2012
  61. app/view/article.js this view has declarative HTML stored in template attribute

    you can define Handlebars.js templates either this way or directly in your HTML file views can also have a layout attribute (see yeild helper ) views can have helpers, see action, log, bindAttr, etc. 1 var ArticleView = Ember.View.extend({ 2 template: Ember.Handlebars.compile( 3 ’<h3>{{content.title}}</h3><p>{{content.content}}</p>’ + 4 ’<a href=”#” {{action goToPublish href=true}}>Publish more!</a>’ 5 ) GeekMeet #12, Cluj-Napoca, Transilvania 13 / 19 Octomber 20th, 2012
  62. app/view/article.js this view has declarative HTML stored in template attribute

    you can define Handlebars.js templates either this way or directly in your HTML file views can also have a layout attribute (see yeild helper ) views can have helpers, see action, log, bindAttr, etc. 1 var ArticleView = Ember.View.extend({ 2 template: Ember.Handlebars.compile( 3 ’<h3>{{content.title}}</h3><p>{{content.content}}</p>’ + 4 ’<a href=”#” {{action goToPublish href=true}}>Publish more!</a>’ 5 ) GeekMeet #12, Cluj-Napoca, Transilvania 13 / 19 Octomber 20th, 2012
  63. app/view/article.js this view has declarative HTML stored in template attribute

    you can define Handlebars.js templates either this way or directly in your HTML file views can also have a layout attribute (see yeild helper ) views can have helpers, see action, log, bindAttr, etc. 1 var ArticleView = Ember.View.extend({ 2 template: Ember.Handlebars.compile( 3 ’<h3>{{content.title}}</h3><p>{{content.content}}</p>’ + 4 ’<a href=”#” {{action goToPublish href=true}}>Publish more!</a>’ 5 ) GeekMeet #12, Cluj-Napoca, Transilvania 13 / 19 Octomber 20th, 2012
  64. app/view/article.js this view has declarative HTML stored in template attribute

    you can define Handlebars.js templates either this way or directly in your HTML file views can also have a layout attribute (see yeild helper ) views can have helpers, see action, log, bindAttr, etc. 1 var ArticleView = Ember.View.extend({ 2 template: Ember.Handlebars.compile( 3 ’<h3>{{content.title}}</h3><p>{{content.content}}</p>’ + 4 ’<a href=”#” {{action goToPublish href=true}}>Publish more!</a>’ 5 ) GeekMeet #12, Cluj-Napoca, Transilvania 13 / 19 Octomber 20th, 2012
  65. Writing tests in JavaScript compared to other programming languages is

    probably the most easy (it might be easier in Ruby), so you have no excuse not to write tests! GeekMeet #12, Cluj-Napoca, Transilvania 14 / 19 Octomber 20th, 2012
  66. Testing tips I prefer Jasmine because. . . it’s just

    one library and it’s easy to set up. for cowboys, check out other solutions always try to use tools to save time, in our case, I suggest you to take a look at Phantom.js tests can be run pragmatically, this saves a lot of time! to keep the project sane and healthy, use some continuous integration solution! take a look at: guard-phantomjs-jasmine http://pivotal.github.com/jasmine/ GeekMeet #12, Cluj-Napoca, Transilvania 15 / 19 Octomber 20th, 2012
  67. Testing tips I prefer Jasmine because. . . it’s just

    one library and it’s easy to set up. for cowboys, check out other solutions always try to use tools to save time, in our case, I suggest you to take a look at Phantom.js tests can be run pragmatically, this saves a lot of time! to keep the project sane and healthy, use some continuous integration solution! take a look at: guard-phantomjs-jasmine http://pivotal.github.com/jasmine/ GeekMeet #12, Cluj-Napoca, Transilvania 15 / 19 Octomber 20th, 2012
  68. Testing tips I prefer Jasmine because. . . it’s just

    one library and it’s easy to set up. for cowboys, check out other solutions always try to use tools to save time, in our case, I suggest you to take a look at Phantom.js tests can be run pragmatically, this saves a lot of time! to keep the project sane and healthy, use some continuous integration solution! take a look at: guard-phantomjs-jasmine http://pivotal.github.com/jasmine/ GeekMeet #12, Cluj-Napoca, Transilvania 15 / 19 Octomber 20th, 2012
  69. Testing tips I prefer Jasmine because. . . it’s just

    one library and it’s easy to set up. for cowboys, check out other solutions always try to use tools to save time, in our case, I suggest you to take a look at Phantom.js tests can be run pragmatically, this saves a lot of time! to keep the project sane and healthy, use some continuous integration solution! take a look at: guard-phantomjs-jasmine http://pivotal.github.com/jasmine/ GeekMeet #12, Cluj-Napoca, Transilvania 15 / 19 Octomber 20th, 2012
  70. Testing tips I prefer Jasmine because. . . it’s just

    one library and it’s easy to set up. for cowboys, check out other solutions always try to use tools to save time, in our case, I suggest you to take a look at Phantom.js tests can be run pragmatically, this saves a lot of time! to keep the project sane and healthy, use some continuous integration solution! take a look at: guard-phantomjs-jasmine http://pivotal.github.com/jasmine/ GeekMeet #12, Cluj-Napoca, Transilvania 15 / 19 Octomber 20th, 2012
  71. Testing tips I prefer Jasmine because. . . it’s just

    one library and it’s easy to set up. for cowboys, check out other solutions always try to use tools to save time, in our case, I suggest you to take a look at Phantom.js tests can be run pragmatically, this saves a lot of time! to keep the project sane and healthy, use some continuous integration solution! take a look at: guard-phantomjs-jasmine http://pivotal.github.com/jasmine/ GeekMeet #12, Cluj-Napoca, Transilvania 15 / 19 Octomber 20th, 2012
  72. Write unit tests for models use describe to explain what

    you are testing use it to describe the test case use beforeEach to DRY aka produce cleaner tests and be fast use multiple describe calls if you want to change the context say, you want to test class methods where before you were testing instance methods 1 describe( ’Article’, function() { 2 3 describe( ’initialization with no values’, function() { 4 var article; 5 6 beforeEach( function() { 7 article = App.Article.create(); 8 } ); 9 10 it( ’has a set of default attributes’, function() { 11 expect( article.get( ’id’ ) ).toMatch( /\d+/ ); 12 expect( article.get( ’title’ ) ).toBeNull(); 13 expect( article.get( ’content’ ) ).toBeNull(); 14 }); 15 16 it( ’throws an exception when calling slug’, function() { 17 expect( function(){ article.get( ’slug’ ) } ).toThrow(); 18 }); 19 20 } ); 21 GeekMeet #12, Cluj-Napoca, Transilvania 16 / 19 Octomber 20th, 2012
  73. Write unit tests for models use describe to explain what

    you are testing use it to describe the test case use beforeEach to DRY aka produce cleaner tests and be fast use multiple describe calls if you want to change the context say, you want to test class methods where before you were testing instance methods 1 describe( ’Article’, function() { 2 3 describe( ’initialization with no values’, function() { 4 var article; 5 6 beforeEach( function() { 7 article = App.Article.create(); 8 } ); 9 10 it( ’has a set of default attributes’, function() { 11 expect( article.get( ’id’ ) ).toMatch( /\d+/ ); 12 expect( article.get( ’title’ ) ).toBeNull(); 13 expect( article.get( ’content’ ) ).toBeNull(); 14 }); 15 16 it( ’throws an exception when calling slug’, function() { 17 expect( function(){ article.get( ’slug’ ) } ).toThrow(); 18 }); 19 20 } ); 21 GeekMeet #12, Cluj-Napoca, Transilvania 16 / 19 Octomber 20th, 2012
  74. Write unit tests for models use describe to explain what

    you are testing use it to describe the test case use beforeEach to DRY aka produce cleaner tests and be fast use multiple describe calls if you want to change the context say, you want to test class methods where before you were testing instance methods 1 describe( ’Article’, function() { 2 3 describe( ’initialization with no values’, function() { 4 var article; 5 6 beforeEach( function() { 7 article = App.Article.create(); 8 } ); 9 10 it( ’has a set of default attributes’, function() { 11 expect( article.get( ’id’ ) ).toMatch( /\d+/ ); 12 expect( article.get( ’title’ ) ).toBeNull(); 13 expect( article.get( ’content’ ) ).toBeNull(); 14 }); 15 16 it( ’throws an exception when calling slug’, function() { 17 expect( function(){ article.get( ’slug’ ) } ).toThrow(); 18 }); 19 20 } ); 21 GeekMeet #12, Cluj-Napoca, Transilvania 16 / 19 Octomber 20th, 2012
  75. Write unit tests for models use describe to explain what

    you are testing use it to describe the test case use beforeEach to DRY aka produce cleaner tests and be fast use multiple describe calls if you want to change the context say, you want to test class methods where before you were testing instance methods 1 describe( ’Article’, function() { 2 3 describe( ’initialization with no values’, function() { 4 var article; 5 6 beforeEach( function() { 7 article = App.Article.create(); 8 } ); 9 10 it( ’has a set of default attributes’, function() { 11 expect( article.get( ’id’ ) ).toMatch( /\d+/ ); 12 expect( article.get( ’title’ ) ).toBeNull(); 13 expect( article.get( ’content’ ) ).toBeNull(); 14 }); 15 16 it( ’throws an exception when calling slug’, function() { 17 expect( function(){ article.get( ’slug’ ) } ).toThrow(); 18 }); 19 20 } ); 21 GeekMeet #12, Cluj-Napoca, Transilvania 16 / 19 Octomber 20th, 2012
  76. Write unit tests for models use describe to explain what

    you are testing use it to describe the test case use beforeEach to DRY aka produce cleaner tests and be fast use multiple describe calls if you want to change the context say, you want to test class methods where before you were testing instance methods 1 describe( ’Article’, function() { 2 3 describe( ’initialization with no values’, function() { 4 var article; 5 6 beforeEach( function() { 7 article = App.Article.create(); 8 } ); 9 10 it( ’has a set of default attributes’, function() { 11 expect( article.get( ’id’ ) ).toMatch( /\d+/ ); 12 expect( article.get( ’title’ ) ).toBeNull(); 13 expect( article.get( ’content’ ) ).toBeNull(); 14 }); 15 16 it( ’throws an exception when calling slug’, function() { 17 expect( function(){ article.get( ’slug’ ) } ).toThrow(); 18 }); 19 20 } ); 21 GeekMeet #12, Cluj-Napoca, Transilvania 16 / 19 Octomber 20th, 2012
  77. Write integration tests for controllers use spy calls aka stubs,

    mocks to isolate tests from other components don’t waste time on writing new (Jasmine) matchers, if your test needs it, rethink it! 1 beforeEach( function() { 2 view = App.PublishView.create(); 3 controller = App.PublishController.create({ 4 namespace: Ember.Object.create({ 5 router: Ember.Object.create({}) 6 }) 7 }); 8 9 view.set( ’controller’, controller ); 10 } ); 11 12 it( ’handles article publication’, function() { 13 var transitionSpy = jasmine.createSpy(); 14 var count = Object.keys( App.Article.all() ).length; 15 var newCount; 16 17 controller.set( ’namespace.router.transitionTo’, transitionSpy ); 18 view.set( ’title’, ’A title’ ); 19 view.set( ’content’, ’Some content...’ ); 20 21 controller.publish.apply( view.get( ’buttonView’ ) ); 22 23 newCount = Object.keys( App.Article.all() ).length; 24 expect( transitionSpy ).toHaveBeenCalled(); GeekMeet #12, Cluj-Napoca, Transilvania 17 / 19 Octomber 20th, 2012
  78. Write integration tests for controllers use spy calls aka stubs,

    mocks to isolate tests from other components don’t waste time on writing new (Jasmine) matchers, if your test needs it, rethink it! 1 beforeEach( function() { 2 view = App.PublishView.create(); 3 controller = App.PublishController.create({ 4 namespace: Ember.Object.create({ 5 router: Ember.Object.create({}) 6 }) 7 }); 8 9 view.set( ’controller’, controller ); 10 } ); 11 12 it( ’handles article publication’, function() { 13 var transitionSpy = jasmine.createSpy(); 14 var count = Object.keys( App.Article.all() ).length; 15 var newCount; 16 17 controller.set( ’namespace.router.transitionTo’, transitionSpy ); 18 view.set( ’title’, ’A title’ ); 19 view.set( ’content’, ’Some content...’ ); 20 21 controller.publish.apply( view.get( ’buttonView’ ) ); 22 23 newCount = Object.keys( App.Article.all() ).length; 24 expect( transitionSpy ).toHaveBeenCalled(); GeekMeet #12, Cluj-Napoca, Transilvania 17 / 19 Octomber 20th, 2012
  79. Questions please. . . Thank you for your time. GeekMeet

    #12, Cluj-Napoca, Transilvania 18 / 19 Octomber 20th, 2012
  80. Some Links To Check TodoMVC – https://github.com/addyosmani/todomvc/ Ember.js – http://emberjs.com/

    Jasmine BDD – http://pivotal.github.com/jasmine/ Idiomatic.js – https://github.com/rwldrn/idiomatic.js/ Phantom.js – http://phantomjs.org/ guard-phantomjs-jasmine – https://github.com/stas/guard-phantomjs-jasmine https: //github.com/stas/emberjs-jasmine-slides-geekmeet GeekMeet #12, Cluj-Napoca, Transilvania 19 / 19 Octomber 20th, 2012