The goal of this app demo is to provide an understanding of BDD and TDD to drive feature-building. In this app, we'll be creating a task list.
Already provided is a basic scaffold for todo items: models and a corresponding migration for the todo, as well as an index page to show the tasks. Notably missing is a route to create todos; this is to simplify the app layout. You can use the seeds file and feature specs to create todos. Setup is simple. Simply run:
rake db:migrate
rake db:seedTo run the app, type in your console:
rails sWhile the server is running, trying poking around the app. Notice there is no way to track task statuses: whether or not a task is complete. This is the first feature we will implement. For now, we can keep them static: they will be set and static upon creation. We want to be able to display a check or empty box for corresponding tasks depending on completion.
First, let's fill out the test that we want to drive development. To run the test we have, try this:
rake cucumberRemember this command; we'll frequently run our tests to check progress.
Already, notice that this test is failing! To find out why, open features/task_display.feature. The test seems to fail because we initialize the database with todos that include a completed field, which doesn't yet exist. Let's make it.
Create a migration using:
rails generate migration AddCompletedToTodoThis generates the migration file, which gets placed in db/migrate/xxx_add_completed_to_todo. Open it.
In the change method, let's add the desired column:
def change
add_column :todos, :completed, :boolean, :default => false
endTo run the migration, type in your console:
rake db:migrateTry running the cucumber test again. They should both be green!
Notice that the two scenarios in features/task_display.feature are empty. This is because we haven't written the expected behavior yet. Fortunately for us, the step definitions have been written; only the feature specs are empty. Let's fill them in for each workflow.
For the first workflow, we want to check that completed tasks contain a check. Underneath the first scenario, paste the following:
Given I am on the home page
Then I should see a checkmark next to "Write section materials."
This will check that a checkmark (defined by any block of text containing "check" in features/step_definitions/todo_steps.rb) appears in the same <tr> row as "Write section materials.".
Similarly, in the second scenario, we want to check that incomplete tasks contain an empty checkbox. Paste the following:
Given I am on the home page
Then I should see a checkbox next to "Cure cancer."
This checks for a checkbox (defined by any block of text containing "unchecked"). To see the complete step definitions, scan features/step_definitions/todo_steps.rb.
If we try to run the tests now, they'll fail! Actually this is what we want as per TDD. For the rest of this app, we'll try to get our newly written feature specs to succeed.
To complete these features, all we need to change is our view in app/views/todos/index.html.erb, since our feature is only a display update. We want to add a new column in the index page.
First, our column header. Inside the <tr> element in the <thead>, add a cell:
<th>Completed</th>This is just the header for the table. To fill out the actual content in <tbody>, we'll add a conditional cell for each row. If a task is completed, this cell should contain <span class="glyphicon glyphicon-check"></span> (which is a nifty Bootstrap icon). Otherwise, it should be <span class="glyphicon glyphicon-unchecked"></span>. Notice that this matches the blocks of text in our step definition from features/step_definitions/todo_steps.rb.
Ultimately, our code in the table should look like this:
<tbody>
<% @todos.each do |todo| %>
<tr>
<td>
<% if todo.completed %>
<span class="glyphicon glyphicon-check"></span>
<% else %>
<span class="glyphicon glyphicon-unchecked"></span>
<% end %>
</td>
<td><%= todo.description %></td>
</tr>
<% end %>
</tbody>Run the tests again. This time, everything should pass! And voila; we're done with this section!