donal
2018-04-25 41951a624e2f2644de49345a59bc40c69a7ee01a
commit | author | age
92e460 1 # Revenge Of The Automated Testing
43f2f2 2
5285f8 3 > The purpose of this lab is to develop and validate a new feature using TDD; and to promote the assured feature through the pipeline.
f6d2bd 4
62a054 5 ![comic-header](../images/exercise3/comic-header.png)
RH 6
7 [Image Source](https://cdn-images-1.medium.com/max/1600/1*wF_fSCH-gLYfMbkwb3gR2w.png)
8
b76e74 9 ## Introduction to TDD.
D 10
11 > _Here is a brief introduction of TDD and why we use it._
12
13 **Test Driven Development (TDD)** is a software development process that relies on the repetition of a very short development cycle. Requirements are turned into test cases, where the software is developed to pass the tests. In other words, it creates a safety net that serves to keep the developer's problems/bugs at bay while enabling the developer to refactor efficiently. This is opposed to software development that allows software to be added that is not proven to meet requirements.
14
15 The TDD cycle can be illustrated with the following diagram;
16 ![TDD-diagram](../images/exercise3/TDD-lifecycle.jpg)
17
18 ### The TDD Cycle 
19
20 1. `Write a test` -
21 In TDD a new feature begins by writing a test. Write a test that clearly defines a function or one that provides an improvement to an existing function. It's important the developer clearly understands the features specification and requirements, or the feature could be wrong from the get-go. 
22
23 2. `Test Fails` -
24 When a test is first implemented it is expected to fail. This failure validates the test is working correctly as the feature is yet to be implemented. 
25
26 3. `Write code to make test pass` -
27 This step involves implementing the feature to pass the failed test. Code written at this stage may be inelegant and still pass the test, however this is acceptable as TDD is a recursive cycle which includes code refactoring.
28
29 4. `Code Passes tests` -
30 If all tests pass, the developer can be confident that the new code meets the test requirements.
31
32 5. `Refactor` -
33 The refactoring step will allow the developer to clean up their code without changing its behaviour. Not changing the behaviour should ensure the tests still pass. The process of refactoring can include; removal of duplication, renaming of Object, class, module, variable and method names to clearly represent their current purpose and use, decoupling of functionality and increasing code cohesion.
34
35 6. `Repeat` -
36 Starting with another new test, the cycle is then repeated to push forward the functionality. The size of the steps should always be small, with as few as 1 to 10 edits between each test run. If new code does not rapidly satisfy a new test, or other tests fail unexpectedly, the programmer should undo or revert in preference to excessive debugging.
37
38 ### Testing Bananalogy
39 Explanation of Mocha and js test syntax through Bananalogy! Imagine for a moment; we're not building software but creating a bowl of fruit. To create a `Bunch of Bananas` component for our fruit bowl we could start with our tests as shown below.
40 ![bdd-bananas](../images/exercise3/bdd-bananas.png)
41   * `describe` is used to group tests together. The string `"a bunch of ripe bananas"` is for human reading and allows you to identify tests.
42   * `it` is a statement that contains a test. It should contain an assertion such as `expect` or `should`. It follows the syntax of `describe` where the string passed in identifies the statement.
f6d2bd 43
D 44 ---
43f2f2 45
D 46 ## Learning Outcomes
f6d2bd 47
43f2f2 48 As a learner you will be able to
f6d2bd 49
5285f8 50 * Understand the why behind TDD
D 51 * Implement a feature using TDD for frontend and backend
52 * Write end to end tests for the feature and run them in CI
43f2f2 53
D 54 ## Tools and Frameworks
f6d2bd 55
43f2f2 56 > Name of tool - short description and link to docs or website
D 57
5285f8 58 1.  [Jest](https://facebook.github.io/jest/) - Zero configuration testing platform
D 59 Jest is used by Facebook to test all JavaScript code including React applications. One of Jest's philosophies is to provide an integrated "zero-configuration" experience. We observed that when engineers are provided with ready-to-use tools, they end up writing more tests, which in turn results in more stable and healthy code bases.
60 1.  [Vue Test Utils](https://vue-test-utils.vuejs.org/en/) - Vue Test Utils is the official unit testing utility library for Vue.js.
61 1.  [Nightwatch.js](http://nightwatchjs.org/) - Nightwatch.js is an easy to use Node.js based End-to-End (E2E) testing solution for browser based apps and websites. It uses the powerful W3C WebDriver API to perform commands and assertions on DOM elements.
62 1.  [Mocha](https://mochajs.org/) - Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases. Hosted on GitHub.
63 1.  [Sinon](http://sinonjs.org/) - Standalone test spies, stubs and mocks for JavaScript. 
64 Works with any unit testing framework.
43f2f2 65
D 66 ## Big Picture
f6d2bd 67
43f2f2 68 This exercise begins cluster containing blah blah
D 69
f6d2bd 70 ---
43f2f2 71
D 72 ## 10,000 Ft View
73
5285f8 74 > The goal of this exercise is to add a new component to the application using TDD to create and validate it's behaviour. The User story we have been given is as follows:
43f2f2 75
5285f8 76 *As a doer I want to mark todos as important so that I can keep track of and complete high prirority todos first*
f6d2bd 77
5285f8 78 _Acceptance Criteria_
D 79 - [ ] should be doable with a single click
80 - [ ] should add a red flag against the todo when marked important
81 - [ ] should remove the red colour flag on the flag when important removed
82 - [ ] should not affect existing todos
83
84 _On page load:_
85 - [ ] should display existing todos that are not marked important
86 - [ ] should display existing todos that are marked important with an red flag
43f2f2 87
D 88 ## Step by Step Instructions
91cc51 89 > This is a fairly structured guide with references to exact filenames and sections of text to be added.
43f2f2 90
f6d2bd 91 ### Part 1 - Tests in our Pipeline
b76e74 92 > _In this part we will get familiar with the layout of our tests. We will also improve the pipeline created already by adding some unit tests for the frontend & backend along with some end to end tests (e2e) to validate the full solution_
43f2f2 93
bc2216 94 #### Part 1a - Unit tests
bc975e 95 > In this exercise we will execute our test for the frontend and backend locally. Once verified we will add them to Jenkins.
bc2216 96
bc975e 97 2. Before linking our automated testing to the pipeline we'll first ensure the tests run locally. Change to the `todolist-fe` directory and run `test`.
91cc51 98 ```bash
A 99 $ cd todolist-fe
100 $ npm run test
101 ```
102 <p class="tip" > 
60bca4 103 `test` is an alias used that runs `vue-cli-service test` from the scripts object in `package.json`
91cc51 104 </p>
b76e74 105 ![screenshot-scripts](../images/exercise3/screenshot-scripts.png)
D 106
107 2. This command will run all `*spec.js` files. Our test files are stored in the following places. There are 12 Frontend test files stored in these directories: `todolist-fe/tests/unit/vue-components/*` & `todolist-fe/tests/unit/javascript/*`
bc2216 108
91cc51 109 2. You should see an output similar to the following. The above command has run a test suite for every `*.spec.js` file. The table generated in the terminal shows the code coverage. We're going to be focusing on the unit tests for now.
b76e74 110 ![test-run-locally](../images/exercise3/test-run-locally.png)
91cc51 111
af284d 112 2. Repeat the same process for `todolist-api` and verify that all the tests run. If you have an ExpressJS server already running from previous exercise; you should kill it before running the tests. The `mocha` test suite will launch a dev server for running the tests. There are 2 Api test files: `todolist-api/server/api/todo/todo.spec.js` & `todolist-api/server/mocks/mock-routes.spec.js` for our API and the Mocks server.
91cc51 113 ```bash
A 114 $ cd todolist-api
115 $ npm run test
116 ```
6e5072 117
a52ae2 118 2. Navigate to your instance of jenkins at `https://jenkins-<YOUR_NAME>-ci-cd.apps.somedomain.com/`. 
91cc51 119 Click on `dev-todolist-fe-build` and then click the `configure` button on the left-hand side.
b76e74 120 ![jenkins-configure-job](../images/exercise3/jenkins-configure-job.png)
91cc51 121
4acca2 122 2. Scroll to the `Build` part of the configuration page and add `npm run test` below `npm install`. Click `save` or `apply` at the bottom to save the changes.
b76e74 123 ![jenkins-build-step](../images/exercise3/jenkins-build-step.png)
91cc51 124
60bca4 125 2. Scroll to the `Post-build Actions` section and click `Add post-build action`. Select `Publish xUnit test result report`.
b76e74 126 ![xunit-action](../images/exercise3/xunit-action.png)
6e5072 127
A 128 2. Click the `Add` button under `Publish xUnit test result report` and select `JUnit`. In the pattern field enter `test-report.xml`. In the `Failed Tests Thresholds`  input box enter 0 under `Red Ball Total`. It should look a little something like this:
b76e74 129 ![post-build-actions](../images/exercise3/post-build-actions.png)
6e5072 130
f56999 131 2. Click `save` or `apply` at the bottom to save the changes. Run the `dev-todolist-fe-build` job and verify that this passes and the `build` and `bake` jobs are both triggered.
6e5072 132
8eeb96 133 2. We're now going to deliberately fail a test to ensure that `bake` and `deploy` jobs aren't triggered if any tests fail. Open the `todolist-fe` source code in your favourite editor. Open `ListOfTodos.spec.js` in `/tests/unit/vue-components` and head to `line 39`. Add `not.` before `toHaveBeenCalled()` to fail the test.
b76e74 134 ![change-test-to-fail](../images/exercise3/change-test-to-fail.png)
6e5072 135
f56999 136 2. Push this to Gitlab and run the build job.
6e5072 137 ```bash
A 138 $ git add .
8eeb96 139 $ git commit -m "TEST - failing build with tests"
6e5072 140 $ git push
A 141 ```
142
143 2. Rerun the `dev-todolist-fe-build` job. It should have failed and not run any other builds. 
b76e74 144 ![jenkins-with-failing-build](../images/exercise3/jenkins-with-failing-build.png)
6e5072 145
2717b2 146 2. Undo the changes you made to the `ListOfTodos.spec.js` file, commit your code and rerun the build. This should trigger a full `build --> bake --> deploy` of `todolist-fe`.
A 147
41951a 148 2. We're now going to do the same for the api. However, in order to run our API tests in CI; we need there to be a MongoDB available for testing. In our `enablement-ci-cd` repo; checkout the mongo branch as shown below to bring in the template and params. The mongodb template we're using is the same as the one for our `todolist-fe` created in previous lab.
D 149 ```bash
150 $ git checkout exercise3/mongodb params/mongodb templates/mongodb.yml
151 ```
2717b2 152
41951a 153 2. Open `enablement-ci-cd` in your favourite editor. Edit the `inventory/host_vars/ci-cd-tooling.yml` to include a new object for our mongodb  as shown below. This item can be added below the jenkins slave in the `ci-cd-builds` section.
D 154 ```yaml
155   - name: "jenkins-mongodb"
156     namespace: "{{ ci_cd_namespace }}"
157     template: "{{ playbook_dir }}/templates/mongodb.yml"
158     params: "{{ playbook_dir }}/params/mongodb"
159     tags:
160     - mongodb
161 ```
162 ![jenkins-mongo](../images/exercise3/jenkins-mongo.png)
163
164 2. Git commit your updates to the inventory to git for traceability.
165 ```bash
166 $ git add .
167 $ git commit -m "ADD - mongodb for use in the pipeline"
168 $ git push
169 ```
170
171 2. Apply this change as done previously using ansible. The deployment can be validated by going to your `<YOUR_NAME>-ci-cd` namespace! 
172 ```bash
173 $ ansible-playbook apply.yml -e target=tools \
174   -i inventory/ \
175   -e "filter_tags=mongodb"
176 ```
177 ![ocp-mongo](../images/exercise3/ocp-mongo.png)
178
179 2. With the mongodb in place Open up Jenkins and head to the `configure` panel of the `dev-todolist-api-build` job. 
180  
4acca2 181 2. Add `npm run test:ci` above `npm run build:ci`.
b76e74 182 ![api-build-step](../images/exercise3/api-build-step.png)
2717b2 183
4f979b 184 2. Scroll to the `Post-build Actions` section and click `Add post-build action`. Select `Publish xUnit test result report`.
2717b2 185
A 186 2. Click the `Add` button under `Publish xUnit test result report` and select `JUnit`. In the pattern field enter `reports/server/mocha/test-results.xml`. In the `Failed Tests Thresholds`  input box enter 0 under `Red Ball Total`. It should look a little something like this:
b76e74 187 ![api-post-build](../images/exercise3/api-post-build.png)
2717b2 188
A 189 2. We're now going to deliberately fail a test again to ensure that `bake` and `deploy` jobs aren't triggered if any tests fail. Go to `todo.spec.js` in `/server/api/todo` and head to `line 35`. Replace `false` with `true`. 
b76e74 190 ![api-fail-build](../images/exercise3/api-fail-build.png)
2717b2 191
f56999 192 2. Push this to Gitlab and run the build job.
2717b2 193 ```bash
A 194 $ git add .
8eeb96 195 $ git commit -m "TEST - failing build with tests"
2717b2 196 $ git push
A 197 ```
198
8eeb96 199 2. If successful this will fail the build and not run the `bake` or `deploy` jobs! Undo your changes and move on to the next section.
f56999 200
A 201 <p class="tip">
202   NOTE - Don't forget to undo the changes that you made to your tests!
203 </p>
2717b2 204
bc2216 205 #### Part 1b - End to End tests (e2e)
3c8f9c 206 > _Unit tests are a great way to get immediate feedback as part of testing an application. End to end tests that drive user behaviour are another amazing way to ensure an application is behaving as expected._
bc2216 207
8529b9 208 In this exercise we will add a new stage to our pipeline called `dev-todolist-fe-e2e` that will run after the deploy has been completed. End to end tests will use Nightwatchjs to orchestrate a selenium webdriver instance that controls the web browser; in this case Chrome!
D 209
210 2. Let's start by checking our tests execute locally. On the terminal move to the `todolist-fe` folder. Our end to end tests are stored in `tests/e2e/specs/`. The vuejs cli uses nightwatch and comes pre-configured to run tests against Chrome. We have created some additional configuration in the root of the project `nightwatch.config.js` to run headless in CI mode on Jenkins.
211 ```bash
212 $ cd todolist-fe
213 ```
214
215 2. Run the tests locally by executing the following. This should start the dev server and run the test. You may see the browser pop up and close while tests execute.
216 ```bash
217 $ npm run e2e
218 ```
e0761f 219 ![local-e2e](../images/exercise3/local-e2e.png)
8529b9 220
e0761f 221 2. With tests executing locally; let's add them to our Jenkins pipeline. To do this; we'll create a new job and connect it up to our `todolist-fe` jobs. Open Jenkins and create a `New Item` called `dev-todolist-fe-e2e`. Make this Job `Freestyle`.
8529b9 222
8eeb96 223 2. On the configuration page; Set the Label for the job to run on as `jenkins-slave-npm`. Check the box marking the build parameterised and add a String parameter of `BUILD_TAG` as done before
e0761f 224 ![e2e-general](../images/exercise3/e2e-general.png)
bc2216 225
e0761f 226 2. On the Source Code Management tab; set the source code to git and add the url to your `todolist-fe` app. Set the branch to `refs/tags/${BUILD_TAG}`
D 227 ![e2e-git](../images/exercise3/e2e-git.png)
228
229 2. Set `Color ANSI Console Output` on the `Build Environment` section 
230
f52b28 231 2. On the Build section; add a build step to execute shell and fill in the followin substituting the domain name and `<YOUR_NAME>` and `somedomain` accordingly:
e0761f 232 ```bash
D 233 export E2E_TEST_ROUTE="http://todolist-fe-<YOUR_NAME>-dev.apps.somedomain.com/"
4acca2 234 npm install
D 235 npm run e2e:ci
e0761f 236 ```
D 237 ![e2e-steps](../images/exercise3/e2e-steps.png)
238
f52b28 239 2. Add a Post Build action to publish Junit test scores and add `reports/e2e/specs/*.xml` to the report location. Save the configuration.
e0761f 240 ![e2e-post-build](../images/exercise3/e2e-post-build.png)
D 241
f52b28 242 2. Finally; connect the e2e job to our dev pipleline by editing the post build actions on `dev-todolist-fe-deploy` job. Set trigger parameterised build on other jobs to be `dev-todolist-fe-e2e`. Add a Parameter and set the it to the `Current build parameters` and save the settings.
7f49cd 243 ![e2e-trigger](../images/exercise3/e2e-trigger.png)
D 244
f52b28 245 2. Run the pipeline from the beginning to see the tests executed (two executions will show tests scores on the graph!).
bc2216 246
5285f8 247 ### Part 2 - TodoList new feature
bc2216 248 > _In this exercise we will introduce a new feature to create an important flag on the todos. In order to be able to build and test our feature we will use TDD_
D 249
5285f8 250 *As a doer I want to mark todos as important so that I can keep track of and complete high prirority todos first*
bc2216 251
5285f8 252 _Acceptance Criteria_
D 253 - [ ] should be doable with a single click
254 - [ ] should add a red flag against the todo when marked important
255 - [ ] should remove the red colour flag on the flag when important removed
256 - [ ] should not affect existing todos
bc2216 257
5285f8 258 _On page load:_
D 259 - [ ] should display existing todos that are not marked important
260 - [ ] should display existing todos that are marked important with an red flag
bc2216 261
3c8f9c 262 #### Part 2a - Create todolist-api tests
5285f8 263 > Using [Mocha](https://mochajs.org/) as our test runner; we will now write some tests for backend functionality to persist our important-flag. The changes required to the backend are minimal but we will use TDD to create our test first, then implement the functionality.
f6d2bd 264
D 265 3.  Create a new branch in your `todolist-api` app for our feature and push it to the remote
bc2216 266 ```bash
D 267 $ git checkout -b feature/important-flag
268 $ git push -u origin feature/important-flag
43f2f2 269 ```
D 270
f6d2bd 271 3.  Navigate to the `server/api/todo/todo.spec.js` file. This contains all of the existing todo list api tests. These are broken down into simple `describe("api definition", function(){})` blocks which is BDD speak for how the component being tested should behave. Inside of each `it("should do something ", function(){})` statements we use some snappy language to illustrate the expected behaviour of the test. For example a `GET` request of the api is described and tested for the return to be of type Array as follows.
D 272 ```javascript
273 describe("GET /api/todos", function() {
274     it("should respond with JSON array", function(done) {
275         request(app)
276         .get("/api/todos")
277         .expect(200)
278         .expect("Content-Type", /json/)
279         .end(function(err, res) {
280             if (err) return done(err);
281             // Test goes here
282             res.body.should.be.instanceof(Array);
283             done();
284         });
5285f8 285       });
f6d2bd 286 });
D 287 ```
288 where:
5285f8 289 _ `describe` is used to group tests together into a collection asserting some feature; for example the get all todos api.
D 290 _ `it` is an individual test statement and should contain an `expect` or a `should` statement asserting behaviour of the API under test.
291 _ `request` is a library for making http calls to the api.
292 _ `.expect(200)` asserts the HTTP Return Code
293 _ `res.body.should.be.instanceof(Array);` is the actual test call
294 _ `done();` tells the test runner that `mocha` has finished execution. This is needed as the http calls are asynchronous.
43f2f2 295
5285f8 296 3.  With this knowledge; let's implement our test for the `important` flag. We expect the fronted to introduce a new property on each `todo` that gets passed to the backend called `important`. The API will need to handle this new property and pass it into the mongodb. Let's begin implementing this functionality by writing our test case. Navigate to the `PUT /api/todos` section of the test which should be at the bottom ![todo-api-tests](../images/exercise3/todo-api-tests.png).
f6d2bd 297
5285f8 298 3.  Before writing our test; let's first make sure all the existing tests are passing.
D 299 ```bash
f6d2bd 300 $ npm run test
D 301 ```
302
5285f8 303 3.  With all the tests passing; let's add our new one. For ease of completing this exercise a template of a new test has been written at the very end of the file. A PUT request responds in our API with the data that it just updated, so provided that MongoDB accepted the change, it will respond with an object that has the `important` property on it. To write our test; edit the `it("should ....", function(done) {` by completing the following:
f6d2bd 304     * Edit the `it("should ...")` to describe the imporant flag we're testing
D 305     * Edit the `.send()` to include `important: true` property
306     * Add a new test assertion to check that `res.body.important` is `true` below the `// YOUR TEST GO HERE` line.
307 ```javascript
5285f8 308 it("should mark todo as important and persist it", function(done) {
f6d2bd 309     request(app)
D 310       .put("/api/todos/" + todoId)
5285f8 311       .send({
D 312         title: "LOVE endpoint/server side testing!",
313         completed: true,
314         important: true
315       })
f6d2bd 316       .expect(200)
D 317       .expect("Content-Type", /json/)
318       .end(function(err, res) {
5285f8 319           if (err) return done(err);
D 320           res.body.should.have.property("_id");
321           res.body.title.should.equal("LOVE endpoint/server side testing!");
322           // YOUR TEST GO HERE
323           res.body.important.should.equal(true);
324           done();
f6d2bd 325       });
5285f8 326 });
f6d2bd 327 ```
D 328
5285f8 329 3.  Run your test. It should fail.
D 330 ```bash
f6d2bd 331 $ npm run test
D 332 ```
333 ![fail-mocha](../images/exercise3/fail-mocha.png)
334
5285f8 335 3.  With our test now failing; let's implement the feature. This is quite a simple change; all we need to do it update the `server/api/todo/todo.model.js` to allow an additional property on the schema called `important` of type Boolean.
f6d2bd 336 ```javascript
D 337 const TodoSchema = new Schema({
5285f8 338   title: String,
D 339   completed: Boolean,
340   important: Boolean
f6d2bd 341 });
D 342 ```
343
5285f8 344 3.  With your changes to the Database schema updated; re-run your tests.
D 345 ```bash
f6d2bd 346 $ npm run test
D 347 ```
348
5285f8 349 3.  Commit your code to the `feature/important-flag` branch and then merge onto the `develop` branch as follows
f6d2bd 350 <p class="tip">
D 351 NOTE - At this point in a residency we would peer review the code before pushing it to develop or master branch!
352 </p>
5285f8 353 ```bash
f6d2bd 354 $ git add .
D 355 $ git commit -m "ADD backend schema updates"
356 $ git checkout develop
357 $ git merge feature/important-flag
358 $ git push --all
359 ```
360
3c8f9c 361 #### Part 2b - Create todolist-fe tests
5285f8 362 > Using [Jest](https://facebook.github.io/jest/) as our test runner and the `vue-test-utils` library for managing our vue components; we will now write some tests for fronted functionality to persist our important-flag. The changes required to the front end are quite large but we will use TDD to create our test first, then implement the functionality. 
f6d2bd 363
5285f8 364 Our TodoList App uses `vuex` to manage the state of the apps' todos and `axios` HTTP library to connect to the backend. `Vuex` is an opinionated framework for managing application state and has some key design features you will need to know to continue with the exercise. 
f6d2bd 365
5285f8 366 In `vuex` the application state is managed by a `store`. The `store` houses all the todos we have retrieved from the backend as well as the `getter` methods for our array of `todos`. In order to make changes to the store, we could call the store directly and update each todo item but as earlier said; vuex is an opinionated module with it's own way of updating the store. It is bad practice to call the store directly. 
D 367
368 There are two parts of the lifecycle to updating the store, the `actions` & `mutations`. When the user clicks a todo to mark it as complete; the `actions` are called. An action could involve a call to the backend or some pre-processing of the data. Once this is done, the change is committed to the store by calling the `mutation` function. A store should only ever be manipulated through a mutation function. Calling the mutation will then update the todo object in the apps local store for rendering in the view.
369
370 For example; when marking a todo as done in the UI, the following flow occurs
371     * The `TodoItem.vue` calls the `markTodoDone()` function which dispatches an event to the store.
372     * This calls the `updateTodo()` function in the `actions.js` file
373     * The action will update the backend db (calling our `todolist-api`) with our updated todo object.
374     * The action will commit the change to the store by calling the mutation method `MARK_TODO_COMPLETED`
375     * The `MARK_TODO_COMPLETED` will directly access the store object and update it with the new state value
376     * The `ListOfTodos.vue` component is watching the store for changes and when something gets updated it re-renders the `TodoItem.vue`.
377
378 3. Let's implement our feature by first creating a branch. Our new feature, important flag will behave in the same way as the `MARK_TODO_COMPLETED`. Create a new branch in your `todolist-fe` app for our feature and push it to the remote
f6d2bd 379 ```bash
D 380 $ git checkout -b feature/important-flag
381 $ git push -u origin feature/important-flag
382 ```
bc2216 383
5285f8 384 3. Let's get our tests running by executing a `--watch` on our tests. This will keep re-running our tests everytime there is a file change. All the tests should be passing when we begin
D 385 ```bash
386 $ npm run test -- --watch
387 ```
388
bc581a 389 3. There are three places we will add new tests to validate our function behaves as expected against the acceptance criteria from Feature Story supplied to us. We will need to write tests for our `TodoItem.vue` to handle having a red flag and that it is clickable. Our app is going to need to persist the changes in the backend so we'll want to make changes to our `actions.js` and `mutations.js` to keep the api and local copy of the store in sync. Let's start with our `TodoItem.vue` component. Open the `tests/unit/vue-components/TodoItem.spec.js` file. This has been templated with some example test to correspond with our A/Cs for speed of doing the lab. Find the describe block for our important flag tests. It is setup already with a `beforeEach()` hook for test setup.
5285f8 390 ![important-flag-before](../images/exercise3/important-flag-before.png)
D 391
392 3. Each of our test cases has it's skeleton in place already for example the `TodoItem.vue` component takes a property of `todos` when rendering. This setup is already done for each of our tests so all we have to do is fill in our assertions.
393 ![todoitem-skeleton-tests](../images/exercise3/todoitem-skeleton-tests.png)
394
395 3. Let's implement the first test `it("should render a button with important flag"`. This test will assert if the button is present on the page and it contains the `.important-flag` CSS class. To implement this; add the expect statement as follows.  
396 ```javascript
397   it("should render a button with important flag", () => {
398     const wrapper = mount(TodoItem, {
399       propsData: { todoItem: importantTodo }
400     });
401     // TODO - test goes here!
402     expect(wrapper.find(".important-flag").exists()).toBe(true);
403   });
404 ```
405
406 3. Save the file and we should see in our test watch the test case has started failing because we have not yet implemented the feature!
407 ![todoitem-fail-test](../images/exercise3/todoitem-fail-test.png)
408
409 3. With a basic assertion in place, let's continue on to the next few tests. We want the important flag to be red when an item in the todolist is marked accordingly. Conversely we want it to be not red when false. Let's create a check for `.red-flag` CSS property to be present when imporant is true and not when false.
410 ```javascript
411   it("should set the colour to red when true", () => {
412     const wrapper = mount(TodoItem, {
413       propsData: { todoItem: importantTodo }
414     });
415     // TODO - test goes here!
416     expect(wrapper.find(".red-flag").exists()).toBe(true);
417   });
418   it("should set the colour to not red when false", () => {
419     importantTodo.important = false;
420     const wrapper = mount(TodoItem, {
421       propsData: { todoItem: importantTodo }
422     });
423     // TODO - test goes here!
424     expect(wrapper.find(".red-flag").exists()).toBe(false);
425   });
426 ```
427
bc581a 428 3. Finally, we want to make the flag clickable and for it to call a function to update the state. The final test in the `TodoItem.spec.js` we want to create should simulate this behaviour. Implement the `it("call makImportant when clicked", () ` test by first simulating the click of our important-flag and asserting the function `markImportant()` to write is executed.
5285f8 429 ```javascript
D 430   it("call makImportant when clicked", () => {
431     const wrapper = mount(TodoItem, {
432       methods,
433       propsData: { todoItem: importantTodo }
434     });
435     // TODO - test goes here!
436     const input = wrapper.find(".important-flag");
437     input.trigger("click");
438     expect(methods.markImportant).toHaveBeenCalled();
439   });
440 ```
441
442 3. With our tests written for the feature's UI component, let's implement our code to pass the tests. Open up the `src/components/TodoItem.vue`. Each vue file is broken down into 3 sections
443     * The `<template></template>` contains the HTML of our component. This could include references to other Components also
444     * The `<script></script>` contains the JavaScript of our component and is essentially the logic for our component. It defines things like `properties`, `methods` and other `components`
445     * The `<style></style>` contains the encapsulated CSS of our component
446 Underneath the `</md-list-item>` tag, let's add a new md-button. Add a `.important-flag` class on the `md-button` and put the svg of the flag provided inside it.
447 ```html
448     </md-list-item>
449     <!-- TODO - SVG for use in Lab3 -->
450     <md-button class="important-flag">
451         <svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" ><path d="M0 0h24v24H0z" fill="none"/><path d="M14.4 6L14 4H5v17h2v-7h5.6l.4 2h7V6z"/></svg>
452     </md-button>
453 ```
454
455 3. We should now see the first of our failing tests has started to pass. Running the app locally (using `npm run serve`) should show the flag appear in the UI. It is clickable but won't fire any events and the colour is not red as per our requirement. Let's continue to implement the colour change for the flag. On our `<svg/>` tag, add some logic to bind the css to the property of a `todo.important` by adding ` :class="{'red-flag': todoItem.important}"  `. This logic will apply the CSS class when `todo.important`  is true.
456 ```html
457 <md-button class="important-flag">
458     <svg :class="{'red-flag': todoItem.important}"  height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" ><path d="M0 0h24v24H0z" fill="none"/><path d="M14.4 6L14 4H5v17h2v-7h5.6l.4 2h7V6z"/></svg>
459 </md-button>
460 ```
461
462 3. More tests should now be passing. Let's wire the click of the flag to an event in Javascript. In the methods section of the `<script></script>` tags in the Vue file, implement the `markImportant()`. We want to wire this to the action to updateTodo, just like we have in the `markCompleted()` call above it. We also need to pass and additional property to this method call `imporant`
463 ```javascript
464     markImportant() {
465       // TODO - FILL THIS OUT IN THE LAB EXERCISE
466       this.$store.dispatch("updateTodo", {id: this.todoItem._id, important: true});
467       console.info("INFO - Mark todo as important ", this.todoItem.important);
468     },
469 ```
470
471 3. Finally - let's connect the click button in the DOM to the Javascript function we've just created. In the template, add a click handler to the md-button to call the function `markImportant()` by adding ` @click="markImportant()"` to the `<md-button> tag 
472 ```html
473     <!-- TODO - SVG for use in Lab3 -->
474     <md-button class="important-flag" @click="markImportant()">
475         <svg :class="{'red-flag': todoItem.important}"  height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" ><path d="M0 0h24v24H0z" fill="none"/><path d="M14.4 6L14 4H5v17h2v-7h5.6l.4 2h7V6z"/></svg>
476     </md-button>
477 ```
478
479 3. The previously failing tests should have started to pass now. With this work done, let's commit our code. On the terminal, run 
480 ```bash
481 $ git add .
482 $ git commit -m "Implementing the todoitem flag"
483 $ git push
484 ```
485
bc581a 486 3. If we try to use our important flag, we should see it's still not behaving as expected; this is because we're not updating the state of the app in response to the click event. We need to implement the `actions` and `mutations` for our feature. Let's start with the tests. Open the `tests/unit/javascript/actions.spec.js` and navigate to the bottom of the file. Our action should should commit the `MARK_TODO_IMPORTANT` to the mutations. Scroll to the end of the test file and implement the skeleton test by adding `expect(commit.firstCall.args[0]).toBe("MARK_TODO_IMPORTANT");` as the assertion.
5285f8 487 ```javascript
D 488   it("should call MARK_TODO_IMPORTANT", done => {
489     const commit = sinon.spy();
490     state.todos = todos;
491     actions.updateTodo({ commit, state }, { id: 1, important: true }).then(() => {
492         // TODO - test goes here!
493         expect(commit.firstCall.args[0]).toBe("MARK_TODO_IMPORTANT");
494         done();
495     });
496   });
497 ```
498
bc581a 499 3. We should now have more failing tests, let's fix this by adding the call from our action to the mutation method. Open the `src/store/actions.js` file and scroll to the bottom to the `updateTodo()` method. Complete the if block by adding `commit("MARK_TODO_IMPORTANT", i);` as shown below.
5285f8 500 ```javascript
D 501 updateTodo({ commit, state }, { id, important }) {
502     let i = state.todos.findIndex(todo => todo._id === id);
503     if (important) {
504         // TODO - add commit imporant here!
505         commit("MARK_TODO_IMPORTANT", i);
506     } else {
507         commit("MARK_TODO_COMPLETED", i);
508     }
509 ```
510
511 3. Finally, let's implement the `mutation` for our feature. Again, starting with the tests..... Open the `tests/unit/javascript/mutations.spec.js`. Our mutation method is responsible to toggling the todo's `important` property between true and 
512 false. Let's implement the tests for this functionality by setting imporant to be true and calling the method expecting the inverse and setting it to false and calling the method expecting the inverse. 
513 ```javascript
514   it("it should MARK_TODO_IMPORTANT as false", () => {
515     state.todos = importantTodos;
516     // TODO - test goes here!
517     mutations.MARK_TODO_IMPORTANT(state, 0);
518     expect(state.todos[0].important).toBe(false);
519   });
520
521   it("it should MARK_TODO_IMPORTANT as true", () => {
522     state.todos = importantTodos;
523     // TODO - test goes here!
524     state.todos[0].important = false;
525     mutations.MARK_TODO_IMPORTANT(state, 0);
526     expect(state.todos[0].important).toBe(true);
527   });
528 ```
529
530 3. With our tests running and failing, let's implement the feature to their spec. Open the `src/store/mutations.js` and add another function called `MARK_TODO_IMPORTANT` below the `MARK_TODO_COMPLETED` to toggle `todo.important` between true and false.
531 ```javascript
532   MARK_TODO_IMPORTANT(state, index) {
533     console.log("INFO - MARK_TODO_IMPORTANT");
534     state.todos[index].important = !state.todos[index].important;
535   }
536 ```
537
538 3. All our tests should now be passing. On the watch tab where they are running, hit `u` to re-run all tests and update any snapshots.
539
540 3. With all our tests now passing, let's commit our code. On the terminal, run
541 ```bash
542 $ git add .
543 $ git commit -m "Implementing the store and actions"
544 $ git push
545 ```
546
547 3. Before running a build in Jenkins, let's add our tests and code to the develop branch
548 <p class="tip">
549 NOTE - At this point in a residency we would peer review the code before pushing it to develop or master branch!
550 </p>
551 ```bash
552 $ git checkout develop
553 $ git merge feature/important-flag
554 $ git push --all
555 ```
556
557 3. Run a build in Jenkins. We should see the test trend increase as we've added more tests. Validate the flag is working as expected.
bc2216 558
3c8f9c 559 #### Part 2c - Create todolist e2e tests
bc2216 560
e0761f 561 3. TODO !!
43f2f2 562
f6d2bd 563 ---
43f2f2 564
D 565 ## Extension Tasks
f6d2bd 566
43f2f2 567 > _Ideas for go-getters. Advanced topic for doers to get on with if they finish early. These will usually not have a solution and are provided for additional scope._
D 568
e0761f 569 * Edit the `dev-todolist-fe-e2e` job so it takes a parameter of the `BUILD_TAG` and only checks out this tag when running the e2e
3c8f9c 570 * Add Config maps to inject DB creds to the app
D 571 * Create a blue/green deploy based on the success of running e2e tests against either blue or green and flopping load over to new endpoint when successful.
572 Advanced
573 * Add Auth0 support to your FE app.
43f2f2 574
D 575 ## Additional Reading
f6d2bd 576
43f2f2 577 > List of links or other reading that might be of use / reference for the exercise
D 578
579 ## Slide links
f6d2bd 580
01c4da 581 - [Intro](https://docs.google.com/presentation/d/18W0GoBTwRGpgbOyHf2ZnL_OIWU_DvsoR14H0_t5jisA)
RH 582 - [Wrap-up](https://docs.google.com/presentation/d/1uIYHC57POSaVD6XNZGhdetABiSnlP1TztYTgglMP-DA)
583 - [All Material](https://drive.google.com/drive/folders/1xVaQukmwwmyJSDN0zOkghZX7yb-0freT)