├── .gitignore
├── README.md
├── dist
└── index.html
├── package-lock.json
├── package.json
├── src
├── components
│ └── List
│ │ ├── List.js
│ │ ├── List.styl
│ │ ├── List.test.js
│ │ ├── NewToDo
│ │ ├── NewToDo.js
│ │ ├── NewToDo.styl
│ │ └── NewToDo.test.js
│ │ └── ToDo
│ │ ├── ToDo.js
│ │ ├── ToDo.styl
│ │ ├── ToDo.test.js
│ │ └── __snapshots__
│ │ └── ToDo.test.js.snap
└── index.js
├── test-config
├── file-mock.js
├── setup.js
└── style-mock.js
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | *.7z
2 | *.key
3 | *.ko
4 | *.log
5 | *.o
6 | *.out
7 | *.pid
8 | *.so
9 | *.swp
10 | *.tar
11 | *~
12 | db
13 | node_modules
14 | typings
15 | tags
16 | x/
17 | coverage
18 | .nyc_output
19 | bundle.js
20 | bundle.js.map
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## react-unit-test-practice
2 |
3 | In this repo lives a simple To Do list that is lacking in testing. The `ToDo` component has a full set of commented example tests to serve as a reference.
4 |
5 | Your goal is to write tests for the other two components and reach 100% code coverage. Remember that 100% coverage doesn't mean perfect tests! Try to find edge cases and errors that may creep up. Not every bit of what you will need is covered in the example tests, you'll need to hit the docs:
6 |
7 | * [Enzyme Docs](http://airbnb.io/enzyme/docs/api/)
8 | * [Jest Docs](https://facebook.github.io/jest/)
9 |
10 | NPM Commands(can all be found in the `package.json`):
11 | * `npm run test` - Runs the test suite a single time
12 | * `npm run test:watch` - Continuously runs the test suite on file change
13 | * `npm run test:coverage` - Prints out a coverage report to console
14 | * `npm run view-coverage` - Launches an HTML view of code coverage, with detailed information on how well pieces of code are covered
15 | * `npm run dev` - Runs the project on port 8080 via webpack dev server with webpack-dashboard
16 | * `npm run prettier` - Why code if it can't be beautiful?
17 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 | );
22 | }
23 |
24 | ToDo.propTypes = {
25 | complete: PropTypes.bool.isRequired,
26 | deleteToDo: PropTypes.func.isRequired,
27 | text: PropTypes.string.isRequired,
28 | toggleCompletion: PropTypes.func.isRequired,
29 | };
30 |
--------------------------------------------------------------------------------
/src/components/List/ToDo/ToDo.styl:
--------------------------------------------------------------------------------
1 | .to-do
2 | align-items center
3 | border-bottom 1px solid black
4 | display flex
5 | font-family "Helvetica Neue", Helvetica, Arial, sans-serif
6 | font-weight 300
7 | height 45px
8 | justify-content space-between
9 | width 530px
10 |
11 | &:last-child
12 | border-bottom none
13 |
14 | .to-do__info--complete
15 | text-decoration line-through
16 |
17 | .to-do__completion
18 | margin-right 50px
--------------------------------------------------------------------------------
/src/components/List/ToDo/ToDo.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import toJson from 'enzyme-to-json';
3 | import { shallow } from 'enzyme';
4 |
5 | import ToDo from './ToDo';
6 |
7 | describe('ToDo', () => {
8 | // Using jest to set up a single unit test.
9 | // The first argument is just an explanation of what the test is,
10 | // this is what will be output while tests run, so make it descriptive.
11 | it('displays text based on props.text', () => {
12 | // Creating a shallow rendered(pared down) version of the component with Enzyme.
13 | const toDo = shallow(
14 | // Ensure props are passed as they would be in production, even if they aren't used in the test.
15 | null}
18 | text="Test ToDo"
19 | toggleCompletion={() => null}
20 | />,
21 | );
22 |
23 | // .find is like document.querySelector, it finds an element based on:
24 | // - Element i.e "button"
25 | // - id or class i.e "#app" ".foo"
26 | // - Component name, if we wanted to find our ToDo component from a parent component: "ToDo"
27 | // Once we have found the element we use the chai-enzyme assertion .to.have.text to check the element text
28 | expect(toDo.find('.to-do__info').text()).toBe('Test ToDo');
29 | });
30 |
31 | it('changes class based on props.completion', () => {
32 | const toDo = shallow(
33 | null}
36 | text="Test ToDo"
37 | toggleCompletion={() => null}
38 | />,
39 | );
40 | const inCompleteToDo = shallow(
41 | null}
44 | text="Test ToDo"
45 | toggleCompletion={() => null}
46 | />,
47 | );
48 |
49 | // The first time this test is run, it will generate a snapshot of the component's output.
50 | // As further changes are made to the component, you simply review the diff to ensure
51 | // that the changes are intentional.
52 | expect(toJson(toDo)).toMatchSnapshot();
53 | // We still need to check both potential states of the component!
54 | expect(toJson(inCompleteToDo)).toMatchSnapshot();
55 | });
56 |
57 | it('ToDo calls props.toggleCompletion on checkbox change', () => {
58 | // Creating a sinon spy,
59 | // essentially a dummy function who's whole purpose is to tell us information about how it is called.
60 | const toggleCompletionSpy = jest.fn();
61 |
62 | // We pass the spy as a prop to the component
63 | const toDo = shallow(
64 | null}
67 | text="Test ToDo"
68 | toggleCompletion={toggleCompletionSpy}
69 | />,
70 | );
71 |
72 | // Enzyme is designed as a UI testing tool,
73 | // which means that rather than manually setting props, it is preferable to use the UI to simulate events.
74 | // Here we find the completion checkbox and simulate a "change" event,
75 | // matching the event handler inside the component.
76 | toDo.find('.to-do__completion').simulate('change');
77 |
78 | // Here we check whether our mocked function has been called the expected number of times
79 | // If we needed to access the arguments we could say
80 | // expect(toggleCompletionSpy).toHaveBeenCalledWith(expectedArguments);
81 | expect(toggleCompletionSpy).toHaveBeenCalled();
82 | });
83 |
84 | it('ToDo calls props.deleteTodo on delete button click', () => {
85 | const deleteToDoSpy = jest.fn();
86 |
87 | const toDo = shallow(
88 | null}
93 | />,
94 | );
95 |
96 | toDo.find('button').simulate('click');
97 |
98 | expect(deleteToDoSpy).toHaveBeenCalled();
99 | });
100 | });
101 |
--------------------------------------------------------------------------------
/src/components/List/ToDo/__snapshots__/ToDo.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`ToDo changes class based on props.completion 1`] = `
4 |
7 |
10 |
16 | Test ToDo
17 |
18 |
23 |
24 | `;
25 |
26 | exports[`ToDo changes class based on props.completion 2`] = `
27 |