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

Test Driven Ember.js

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

Test Driven Ember.js

Ember.js is JavaScript framework for building feature rich and very responsive applications. This session will provide an overview of Ember.js and demonstrate test-driven development of single-page web applications.

In this session, I will present a walkthrough of Ember.js core features. I will showcase a test-driven development of Ember.js application using Mocha. I will also explain Ember.js’ data bindings that allow for creation of views that update automatically in response to model changes. I will demo ease of Ember.js and Rails integration. Finally, I will utilize Ember.js components to create reusable UI elements.

In summary, Ember.js is a great framework for creating complex single-page applications. Attendees will leave the talk with a solid understanding of Ember.js test-driven development process.

Avatar for AntiTyping

AntiTyping

March 18, 2014
Tweet

More Decks by AntiTyping

Other Decks in Programming

Transcript

  1. jQuery everywhere • Low-level DOM modification • Copy and paste

    code • Lack of structure • Maintenance nightmare • Hard to test @AntiTyping
  2. Tools • Node.js • npm • Grunt • Bower •

    Yeoman • Lineman @AntiTyping
  3. Installation • brew install nodejs • npm install -g yo

    • npm install -g generator-ember @AntiTyping
  4. yo ember • mkdir EmberApp && cd $_ • yo

    ember • yo ember:controller create a new web app @AntiTyping
  5. Mocha/Chai • Behavior-driven development framework • Specs for your JavaScript

    code • Write expectations • Uses matchers @AntiTyping
  6. Mocha Suites describe("A suite", function() { var flag; ! beforeEach(function()

    { flag = true; }); ! it("contains spec with an expectation", function() { expect(flag).should.equal(true); }); }); @AntiTyping
  7. Chai Expectations describe("A suite", function() { it("contains spec with an

    expectation", function() { expect(true).to.equal(true); }); }); @AntiTyping
  8. Chai Matchers foo.should.be.a('string'); foo.should.equal('bar'); foo.should.have.length(3); tea.should.have.property('flavors') .with.length(3); ! expect(foo).to.be.a('string'); expect(foo).to.equal('bar');

    expect(foo).to.have.length(3); expect(tea).to.have.property('flavors') .with.length(3); ! assert.typeOf(foo, 'string'); assert.equal(foo, 'bar'); assert.lengthOf(foo, 3) assert.property(tea, 'flavors'); assert.lengthOf(tea.flavors, 3); expect(bar).toThrow(); @AntiTyping
  9. Features •Display list of tasks •Add a new task •Mark

    task as done •Add a new task with a priority •Filter tasks by priority •Search tasks •Task counter @AntiTyping
  10. Install dependencies • rvm install 2.0 • gem install compass

    • brew install nodejs • npm install -g bower • npm install -g yo • npm install -g generator-ember • npm install -g karma @AntiTyping
  11. EmberDo front-end • git clone [email protected]:AntiTyping/EmberDo.git • cd EmberDo •

    npm install • bower install • cd test && bower install && cd .. • grunt server @AntiTyping
  12. User story As a user, I should be able to

    see list of tasks, so I can choose the next task to do ! Scenario: Display list of tasks When I navigate to the task list Then I should see the list of tasks @AntiTyping
  13. Scenario describe("Task List", function() { it('should display list of tasks',

    function() { expect($('tr.task')).to.have.length(3); }); }); @AntiTyping
  14. Model Todos.Todo = DS.Model.extend({ name: DS.attr("string"), priority: DS.attr("string") }); !

    Todos.Todo.FIXTURES = [ {id: 1, name: "Hight priority task", priority: "high"}, {id: 2, name: "Medium priority task", priority: "medium"}, {id: 3, name: "Low priority task", priority: "low"} ]; @AntiTyping
  15. Feature #1 Summary • Scenario • List of tasks (#each)

    • Todos route (TodosRoute) • Todo model • No low level DOM manipulation (#each) @AntiTyping
  16. User Story As a user, I should be able to

    add a new task, so I can update my list of tasks ! Scenario: Add a valid new task When I add a valid new task Then I should see the task in the list ! Scenario: Add an invalid new task When I add an invalid new task Then I should see an error message @AntiTyping
  17. :) Path Scenario describe("Add a new task", function() { describe("when

    the new task is valid", function() { it("should add it to the list", function() { expect($('tr.task:last').text()).to.match(/New task/); expect($('tr.task')).to.have.length(4); }); it('should clear the new task box', function() { expect($('.task-name').val()).to.equal(''); }); it("should not display an error message", function() { expect($('div.alert').hasClass('hide')).to.be.true; }); }); @AntiTyping
  18. :( Path Scenario describe("when the new task is invalid", function()

    { it("should leave the task list unchanged", function() { expect($('tr.task')).to.have.length(3); }); it("should display an error message", function() { expect($('div.alert').hasClass('hide')).to.be.false; }); @AntiTyping
  19. TodosController Todos.TodosController = Ember.ArrayController.extend({ actions: { createTodo: function() { var

    name = this.get('newName'); ! . . . ! var todo = this.store.createRecord('todo', { name: name }); this.set('newName', ''); ! todo.save(); } } }); @AntiTyping
  20. Feature #2 Summary • Scenarios • Added {{input}} • Added

    {{action}} • Dynamic list (#each) @AntiTyping
  21. User Story As a user, I should be able to

    mark tasks as done, so I can keep track of completed work ! Scenario: Mark task as done When I mark a task as done Then the task should be remove from the list ! @AntiTyping
  22. Scenario describe("Marking task as done", function() { it("should remove the

    task from the task list", function() { $('button.js-done:last').click(); expect($('tr.task')).to.have.length(2); }); }); @AntiTyping
  23. removeTodo() Todos.TodoController = Ember.ObjectController.extend({ actions: { removeTodo: function() { var

    todo = this.get('model'); todo.deleteRecord(); todo.save(); } } }); <tbody> {{#each itemController='todo'}} <tr class="task"> . . . <td> <button {{action "removeTodo"}} . . .>Done</button> </td> </tr> {{/each}} </tbody>
  24. User story As a user, I should be able to

    set task priority, so I can keep track of urgent tasks ! Scenario: Add a task with priority When I add task with priority Then the task list should include priorities ! @AntiTyping
  25. {{priority}} {{#each itemController='todo'}} <tr class="task"> <td>{{_view.contentIndex}}</td> <td> {{name}} <span class="priority

    label">{{priority}}</span> </td> <td> <button {{action “removeTodo"}} . . .>Done</button> </td> </tr> {{/each}} @AntiTyping
  26. Property createTodo: function() { var name = this.get('newName'); var priority

    = this.get(‘priority'); ! . . . ! var todo = this.store.createRecord('todo', { name: name, priority: priority }); ! this.set('newName', ''); todo.save(); } @AntiTyping
  27. User Story As a user, I should be filter tasks

    by priority, so I can find hight priority tasks ! Scenario: Priority filter When I select ‘high’ priority filter Then I should see only high priority tasks ! @AntiTyping
  28. Scenario describe("Filter by priority", function() { describe("when high priority is

    selected", function() { it("should display only high priority tasks", function() { $("a.priority:contains('High')").click(); expect($('tr.task')).to.have.length(1); }); }); ! . . . ! describe("when no priority is selected", function() { it("should display all tasks", function() { $("a.priority:contains('All')").click(); expect($('tr.task')).to.have.length(3); }); }); }); @AntiTyping
  29. {{#link-to}} <div class="well" style="max-width: 340px; padding: 8px 0;"> <ul class="nav

    nav-list"> <li class="nav-header">Priority</li> <li> {{#link-to "todos.index" class="priority"}}All{{/link-to}} </li> <li> {{#link-to "todos.high" class="priority"}}High{{/link-to}} </li> <li> {{#link-to "todos.medium" class="priority"}}Medium{{/link-to}} </li> <li> {{#link-to "todos.low" class="priority"}}Low{{/link-to}} </li> </ul> @AntiTyping
  30. Router Todos.Router.map(function() { this.resource('todos', { path: '/' }, function() {

    this.route("high"); this.route("medium"); this.route("low"); }); }); @AntiTyping
  31. Route Todos.TodosHighRoute = Todos.TodosPriorityRoute.extend({ model: function() { return this.filterByPriority('high'); },

    }); ! ! ! Todos.TodosPriorityRoute = Ember.Route.extend({ controllerName: 'Todos', renderTemplate: function(controller) { this.render('todos/index', {controller: controller}); }, filterByPriority: function(priority) { return this.store.filter('todo', function(todo) { return todo.get('priority') == priority; }); } }); !
  32. Summary • Ember abstracts away DOM • Outside in TDD

    • Red-Green-Refactor • Structure development workflow • AngularJS talk @AntiTyping