Add a Todo

Story: As a user, I want to add a todo to my todos list

Since this is our first story, we'll need to create some scaffolding to complete it. It will probably be our largest single story, creating basic React/Redux structures like Actions, Action Types, the Reducer, and the Component hierarchy, all the way up to the top-level Container. In a real project team, we might choose to split this story into several sub-stories or sub-tasks that can each be completed by a separate engineer, in parallel.

TodoMVC actions

It should create an action to add a todo

Write the test.

// tests/todomvc/actions.spec.js

'use strict';

import {expect} from 'chai'

import todomvc from '../../src/todomvc'

describe('TodoMVC actions', () => {
  it('Should create an action to add a todo', () => {
    const description = 'My todo';
    const expectedAction = {
      type: 'todomvc/ADD', description: description, completed: false
    };

    expect(todomvc.actions.addTodo(description)).to.deep.equal(expectedAction)
  })
});

Run the test and watch it fail.

Write the code to make the test pass. In this case, the test failed because we haven't yet written any production code, so we couldn't find the todomvc module.

We will also need to a place to define our action type constants:

Finally, we will need to create an index file to export modules from our application:

Run the test and watch it pass.

Commit changes.

TodoMVC reducer

It should handle initial state

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

And export the new reducer from the application.

Run the test and watch it pass.

Commit changes.

It should handle ADD todo

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass.

Commit changes.

TodoTextInput component

It should render correctly

It should be a TodoTextInput component

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass.

Commit changes.

Should behave correctly

It should update value on change

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass.

Commit changes.

It should call onSave() on return key press

Write the test. We need to import sinon to spy on the onSave

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass.

Commit changes.

It should reset state on return key press if isNew

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass.

Commit changes.

It should call onSave() on blur if not isNew

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass.

Commit changes.

It should not call onSave() on blur if isNew

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass.

Commit changes.

Header component

Should render correctly

It should be a Header component

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass.

Commit changes.

It should have a title

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass.

Commit changes.

It should have a TodoTextInput field

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass. Note the warning, below. We'll implement onSave in the next test.

Commit changes.

Should behave correctly

It should call addTodo() if length of text is greater than 0

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass.

Commit changes.

TodoApp component

This is the top-level container component of our application. To render it, we'll need a Redux store. However, we don't want to pull the whole application template into these tests. Instead, we'll just create our own, simple Redux store using our existing reducer.

Interestingly, there is not a lot to test in this component, since it's mostly just responsible for rendering its child components and passing them the mapped store and actions.

Should render correctly

It should have a Header

Write the test.

Run the test and watch it fail.

Write the code to make the test pass.

Run the test and watch it pass.

Commit changes.

Tie everything together

Commit changes.

Run It!

Now let's see what this looks like.

Open http://localhost:4000 in your web browser.

Type "Hello" into the text input box and see what happens. Then enter "World" You can watch state update with each action in the Redux Dev Tools window on the right, like this:

Last updated

Was this helpful?