Testing Your Sproutcore Presentation

  • 1,472 views
Uploaded on

How to test your Sproutcore application using BDD.

How to test your Sproutcore application using BDD.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,472
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
28
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

Transcript

  • 1. How do I test my Sproutcore Application? Greg Moeck
  • 2. @gregmoeck
  • 3. Quick Poll
  • 4. Question 1
  • 5. Full TimeSproutcore?
  • 6. Full TimeJavaScript?
  • 7. Other?
  • 8. Question 2
  • 9. PracticeTDD/BDD?
  • 10. PracticeTest Last UnitTesting?
  • 11. NoAutomated Tests?
  • 12. Question 3
  • 13. Practice TDD/BDDIn JS / SC?
  • 14. What We Want InOur Tests
  • 15. EnsureApplication Behavior
  • 16. All Objects Work Together
  • 17. All Objects WorkIndividually
  • 18. All Objects Work Together Acceptance/Integration Tests
  • 19. All Objects Work Individually Unit Tests
  • 20. “ Unit Tests Tell You That You Built The System Right. Acceptance / Integration Tests Tell You That You’ve Built The Right System Gojko Adzic, Specification by Example
  • 21. Integration Tests
  • 22. EnsuresValue ForThe User
  • 23. Use TheSystem As The User Would
  • 24. Scenario(Searching For An Item, function() { Given(an auction item that is available for sale, function() { var itemTitle = item; beforeEach(function() { Fictum.addResource(Item, {title: itemTitle}); }); When(I search for that auction item, function() { beforeEach(function() { Simulo.fillIn(#mainSearchWidget input[type="text"], itemTitle); Simulo.clickOn(#mainSearchWidget .submit-search); }); Then(I should see the auction item within the search results, function(page) { page.within(.search-results, function(page) { expect(page).toHaveContent(itemTitle); }); }); }); }); });});
  • 25. Scenario(Searching For An Item, function() { Given(an auction item that is available for sale, function() { var itemTitle = item; beforeEach(function() { Fictum.addResource(Item, {title: itemTitle}); }); When(I search for that auction item, function() { beforeEach(function() { Simulo.fillIn(#mainSearchWidget input[type="text"], itemTitle); Simulo.clickOn(#mainSearchWidget .submit-search); }); Then(I should see the auction item within the search results, function(page) { page.within(.search-results, function(page) { expect(page).toHaveContent(itemTitle); }); }); }); }); });});
  • 26. Scenario(Searching For An Item, function() { Given(an auction item that is available for sale, function() { var itemTitle = item; beforeEach(function() { Fictum.addResource(Item, {title: itemTitle}); }); When(I search for that auction item, function() { beforeEach(function() { Simulo.fillIn(#mainSearchWidget input[type="text"], itemTitle); Simulo.clickOn(#mainSearchWidget .submit-search); }); Then(I should see the auction item within the search results, function(page) { page.within(.search-results, function(page) { expect(page).toHaveContent(itemTitle); }); }); }); }); });});
  • 27. Scenario(Searching For An Item, function() { Given(an auction item that is available for sale, function() { var itemTitle = item; beforeEach(function() { Fictum.addResource(Item, {title: itemTitle}); }); When(I search for that auction item, function() { beforeEach(function() { Simulo.fillIn(#mainSearchWidget input[type="text"], itemTitle); Simulo.clickOn(#mainSearchWidget .submit-search); }); Then(I should see the auction item within the search results, function(page) { page.within(.search-results, function(page) { expect(page).toHaveContent(itemTitle); }); }); }); }); });});
  • 28. Scenario(Searching For An Item, function() { Given(an auction item that is available for sale, function() { var itemTitle = item; beforeEach(function() { Fictum.addResource(Item, {title: itemTitle}); }); When(I search for that auction item, function() { beforeEach(function() { Simulo.fillIn(#mainSearchWidget input[type="text"], itemTitle); Simulo.clickOn(#mainSearchWidget .submit-search); }); Then(I should see the auction item within the search results, function(page) { page.within(.search-results, function(page) { expect(page).toHaveContent(itemTitle); }); }); }); }); });});
  • 29. Scenario(Searching For An Item, function() { Given(an auction item that is available for sale, function() { var itemTitle = item; beforeEach(function() { Fictum.addResource(Item, {title: itemTitle}); }); When(I search for that auction item, function() { beforeEach(function() { Simulo.fillIn(#mainSearchWidget input[type="text"], itemTitle); Simulo.clickOn(#mainSearchWidget .submit-search); }); Then(I should see the auction item within the search results, function(page) { page.within(.search-results, function(page) { expect(page).toHaveContent(itemTitle); }); }); }); }); });});
  • 30. Scenario(Searching For An Item, function() { Given(an auction item that is available for sale, function() { var itemTitle = item; beforeEach(function() { Fictum.addResource(Item, {title: itemTitle}); }); When(I search for that auction item, function() { beforeEach(function() { Simulo.fillIn(#mainSearchWidget input[type="text"], itemTitle); Simulo.clickOn(#mainSearchWidget .submit-search); }); Then(I should see the auction item within the search results, function(page) { page.within(.search-results, function(page) { expect(page).toHaveContent(itemTitle); }); }); }); }); });});
  • 31. Scenario(Searching For An Item, function() { Given(an auction item that is available for sale, function() { var itemTitle = item; beforeEach(function() { Fictum.addResource(Item, {title: itemTitle}); }); When(I search for that auction item, function() { beforeEach(function() { Simulo.fillIn(#mainSearchWidget input[type="text"], itemTitle); Simulo.clickOn(#mainSearchWidget .submit-search); }); Then(I should see the auction item within the search results, function(page) { page.within(.search-results, function(page) { expect(page).toHaveContent(itemTitle); }); }); }); }); });});
  • 32. UnitTests
  • 33. EnsuresValue Of TheArchitecture
  • 34. Use Object Like ACollaborator Would
  • 35. Isolate TheObject
  • 36. Example:Testing A View
  • 37. TestThroughView API
  • 38. TotalFlow
  • 39. Example
  • 40. sc-init todos --template
  • 41. install jasmine-sproutcorehttps://github.com/gmoeck/jasmine- sproutcore
  • 42. install simulohttps://github.com/gmoeck/simulo
  • 43. describe(Scenario: Adding a todo, function() { Given(I have loaded the todo application, function() { afterEach(function() { Todos.mainPane.remove(); }); When(I add a new todo item, function() { var description; beforeEach(function() { description = Do Something; Simulo.fillIn(#new-todo, description).pressEnter(); }); Then(I should see the item in the list of available items, function(page) { page.within(#incomplete-todos, function(page) { expect(page).toHaveContent(description); }); }); }); });});
  • 44. describe(Scenario: Adding a todo, function() { Given(I have loaded the todo application, function() { afterEach(function() { Todos.mainPane.remove(); }); When(I add a new todo item, function() { var description; beforeEach(function() { description = Do Something; Simulo.fillIn(#new-todo, description).pressEnter(); }); Then(I should see the item in the list of available items, function(page) { page.within(#incomplete-todos, function(page) { expect(page).toHaveContent(description); }); }); }); });});
  • 45. describe(Scenario: Adding a todo, function() { Given(I have loaded the todo application, function() { afterEach(function() { Todos.mainPane.remove(); }); When(I add a new todo item, function() { var description; beforeEach(function() { description = Do Something; Simulo.fillIn(#new-todo, description).pressEnter(); }); Then(I should see the item in the list of available items, function(page) { page.within(#incomplete-todos, function(page) { expect(page).toHaveContent(description); }); }); }); });});
  • 46. describe(Scenario: Adding a todo, function() { Given(I have loaded the todo application, function() { afterEach(function() { Todos.mainPane.remove(); }); When(I add a new todo item, function() { var description; beforeEach(function() { description = Do Something; Simulo.fillIn(#new-todo, description).pressEnter(); }); Then(I should see the item in the list of available items, function(page) { page.within(#incomplete-todos, function(page) { expect(page).toHaveContent(description); }); }); }); });});
  • 47. describe(Scenario: Adding a todo, function() { Given(I have loaded the todo application, function() { afterEach(function() { Todos.mainPane.remove(); }); When(I add a new todo item, function() { var description; beforeEach(function() { description = Do Something; Simulo.fillIn(#new-todo, description).pressEnter(); }); Then(I should see the item in the list of available items, function(page) { page.within(#incomplete-todos, function(page) { expect(page).toHaveContent(description); }); }); }); });});
  • 48. describe(Scenario: Adding a todo, function() { Given(I have loaded the todo application, function() { afterEach(function() { Todos.mainPane.remove(); }); When(I add a new todo item, function() { var description; beforeEach(function() { description = Do Something; Simulo.fillIn(#new-todo, description).pressEnter(); }); Then(I should see the item in the list of available items, function(page) { page.within(#incomplete-todos, function(page) { expect(page).toHaveContent(description); }); }); }); });});
  • 49. describe(Scenario: Adding a todo, function() { Given(I have loaded the todo application, function() { afterEach(function() { Todos.mainPane.remove(); }); When(I add a new todo item, function() { var description; beforeEach(function() { description = Do Something; Simulo.fillIn(#new-todo, description).pressEnter(); }); Then(I should see the item in the list of available items, function(page) { page.within(#incomplete-todos, function(page) { expect(page).toHaveContent(description); }); }); }); });});
  • 50. describe(Scenario: Adding a todo, function() { Given(I have loaded the todo application, function() { afterEach(function() { Todos.mainPane.remove(); }); When(I add a new todo item, function() { var description; beforeEach(function() { description = Do Something; Simulo.fillIn(#new-todo, description).pressEnter(); }); Then(I should see the item in the list of available items, function(page) { page.within(#incomplete-todos, function(page) { expect(page).toHaveContent(description); }); }); }); });});
  • 51. describe(Scenario: Adding a todo, function() { Given(I have loaded the todo application, function() { afterEach(function() { Todos.mainPane.remove(); }); When(I add a new todo item, function() { var description; beforeEach(function() { description = Do Something; Simulo.fillIn(#new-todo, description).pressEnter(); }); Then(I should see the item in the list of available items, function(page) { page.within(#incomplete-todos, function(page) { expect(page).toHaveContent(description); }); }); }); });});
  • 52. resources/templates/todos.handlebars<h1>Todos</h1>{{#view Todos.CreateTodoView}} <input id="new-todo" type="text" placeholder="What needs to be done?" >{{/view}}
  • 53. Error
  • 54. Error
  • 55. views/create_todo_view.jsTodos.CreateTodoView = SC.TemplateView.extend({});
  • 56. resources/templates/todos.handlebars<h1>Todos</h1>{{#view Todos.CreateTodoView}} <input id="new-todo" type="text" placeholder="What needs to be done?" >{{/view}}{{#collection Todos.TodoListView id="incomplete-todos"}} {{content.title}}{{/collection}}
  • 57. views/todo_list_view.jsTodos.TodoListView = SC.TemplateCollectionView.extend({});
  • 58. tests/unit/views/create_todo_view_spec.js describe(Todos.CreateTodoView, function() { describe(#insertNewline, function() { var createTodoSpy, value; beforeEach(function() { value = Do Something; view = Todos.CreateTodoView.create({value: value}); createTodoSpy = spyOn(Todos.todoListController, createTodo); view.insertNewline(); }); it(delegates to create a new todo with its current value, function() { expect(createTodoSpy).toHaveBeenCalledWith(value); }); });
  • 59. tests/unit/views/create_todo_view_spec.js describe(Todos.CreateTodoView, function() { describe(#insertNewline, function() { var createTodoSpy, value; beforeEach(function() { value = Do Something; view = Todos.CreateTodoView.create({value: value}); createTodoSpy = spyOn(Todos.todoListController, createTodo); view.insertNewline(); }); it(delegates to create a new todo with its current value, function() { expect(createTodoSpy).toHaveBeenCalledWith(value); }); });
  • 60. tests/unit/views/create_todo_view_spec.js describe(Todos.CreateTodoView, function() { describe(#insertNewline, function() { var createTodoSpy, value; beforeEach(function() { value = Do Something; view = Todos.CreateTodoView.create({value: value}); createTodoSpy = spyOn(Todos.todoListController, createTodo); view.insertNewline(); }); it(delegates to create a new todo with its current value, function() { expect(createTodoSpy).toHaveBeenCalledWith(value); }); });
  • 61. tests/unit/views/create_todo_view_spec.js describe(Todos.CreateTodoView, function() { describe(#insertNewline, function() { var createTodoSpy, value; beforeEach(function() { value = Do Something; view = Todos.CreateTodoView.create({value: value}); createTodoSpy = spyOn(Todos.todoListController, createTodo); view.insertNewline(); }); it(delegates to create a new todo with its current value, function() { expect(createTodoSpy).toHaveBeenCalledWith(value); }); });
  • 62. tests/unit/views/create_todo_view_spec.js describe(Todos.CreateTodoView, function() { describe(#insertNewline, function() { var createTodoSpy, value; beforeEach(function() { value = Do Something; view = Todos.CreateTodoView.create({value: value}); createTodoSpy = spyOn(Todos.todoListController, createTodo); view.insertNewline(); }); it(delegates to create a new todo with its current value, function() { expect(createTodoSpy).toHaveBeenCalledWith(value); }); });
  • 63. tests/unit/views/create_todo_view_spec.js describe(Todos.CreateTodoView, function() { describe(#insertNewline, function() { var createTodoSpy, value; beforeEach(function() { value = Do Something; view = Todos.CreateTodoView.create({value: value}); createTodoSpy = spyOn(Todos.todoListController, createTodo); view.insertNewline(); }); it(delegates to create a new todo with its current value, function() { expect(createTodoSpy).toHaveBeenCalledWith(value); }); });
  • 64. tests/unit/views/create_todo_view_spec.js describe(Todos.CreateTodoView, function() { describe(#insertNewline, function() { var createTodoSpy, value; beforeEach(function() { value = Do Something; view = Todos.CreateTodoView.create({value: value}); createTodoSpy = spyOn(Todos.todoListController, createTodo); view.insertNewline(); }); it(delegates to create a new todo with its current value, function() { expect(createTodoSpy).toHaveBeenCalledWith(value); }); });
  • 65. Todos.todoListController.createTodo
  • 66. controllers/todo_list_controller.jsTodos.todoListController = SC.ArrayController.create({ createTodo: function(title) { }});
  • 67. views/create_todo_view.jsTodos.CreateTodoView = SC.TemplateView.extend(SC.TextFieldSupport, { insertNewline: function() { }});
  • 68. views/create_todo_view.jsTodos.CreateTodoView = SC.TemplateView.extend(SC.TextFieldSupport, { insertNewline: function() { Todos.todoListController.createTodo(this.get(value)); }});
  • 69. Should be different, but we already definedTodos.todoListController.
  • 70. tests/unit/controllers/todo_list_controller_spec.jsdescribe(Todos.todoListController, function() { describe(#createTodo, function() { var createTodoSpy, title; beforeEach(function() { title = title; createTodoSpy = spyOn(Todos.Todo, create); Todos.todoListController.createTodo(title); }); it(creates a todo with the passed in title, function() { expect(createTodoSpy).toHaveBeenCalledWith({title: title}); }); });});
  • 71. tests/unit/controllers/todo_list_controller_spec.jsdescribe(Todos.todoListController, function() { describe(#createTodo, function() { var createTodoSpy, title; beforeEach(function() { title = title; createTodoSpy = spyOn(Todos.Todo, create); Todos.todoListController.createTodo(title); }); it(creates a todo with the passed in title, function() { expect(createTodoSpy).toHaveBeenCalledWith({title: title}); }); });});
  • 72. tests/unit/controllers/todo_list_controller_spec.jsdescribe(Todos.todoListController, function() { describe(#createTodo, function() { var createTodoSpy, title; beforeEach(function() { title = title; createTodoSpy = spyOn(Todos.Todo, create); Todos.todoListController.createTodo(title); }); it(creates a todo with the passed in title, function() { expect(createTodoSpy).toHaveBeenCalledWith({title: title}); }); });});
  • 73. tests/unit/controllers/todo_list_controller_spec.jsdescribe(Todos.todoListController, function() { describe(#createTodo, function() { var createTodoSpy, title; beforeEach(function() { title = title; createTodoSpy = spyOn(Todos.Todo, create); Todos.todoListController.createTodo(title); }); it(creates a todo with the passed in title, function() { expect(createTodoSpy).toHaveBeenCalledWith({title: title}); }); });});
  • 74. tests/unit/controllers/todo_list_controller_spec.jsdescribe(Todos.todoListController, function() { describe(#createTodo, function() { var createTodoSpy, title; beforeEach(function() { title = title; createTodoSpy = spyOn(Todos.Todo, create); Todos.todoListController.createTodo(title); }); it(creates a todo with the passed in title, function() { expect(createTodoSpy).toHaveBeenCalledWith({title: title}); }); });});
  • 75. tests/unit/controllers/todo_list_controller_spec.jsdescribe(Todos.todoListController, function() { describe(#createTodo, function() { var createTodoSpy, title; beforeEach(function() { title = title; createTodoSpy = spyOn(Todos.Todo, create); Todos.todoListController.createTodo(title); }); it(creates a todo with the passed in title, function() { expect(createTodoSpy).toHaveBeenCalledWith({title: title}); }); });});
  • 76. Todos.Todo.create
  • 77. models/todo.jsTodos.Todo = SC.Object.extend({});
  • 78. controllers/todo_list_controller.jsTodos.todoListController = SC.ArrayController.create({ createTodo: function(title) { Todos.Todo.create({title: title}); }});
  • 79. tests/unit/controllers/todo_list_controller_spec.jsdescribe(Todos.todoListController, function() { describe(#createTodo, function() { var createTodoSpy, title, todo; beforeEach(function() { title = title; todo = {title: title}; createTodoSpy = spyOn(Todos.Todo, create).andReturn(todo); Todos.todoListController.createTodo(title); }); ... it(adds that todo to its content, function() { expect(Todos.todoListController.get(content)).toContain(todo); }); });});
  • 80. controllers/todo_list_controller.jsTodos.todoListController = SC.ArrayController.create({ content: [], createTodo: function(title) { Todos.Todo.create({title: title}); }});
  • 81. controllers/todo_list_controller.jsTodos.todoListController = SC.ArrayController.create({ content: [], createTodo: function(title) { var todo = Todos.Todo.create({title: title}); this.pushObject(todo); }});
  • 82. Questions?gmoeck@gmail.com @gregmoeck