|
| 1 | +# Continuous integration and testing |
| 2 | + |
| 3 | +Chances are you've heard the abbreviation CI/CD, which stands for continuous integration and continuous delivery (or sometimes continuous deployment). CI is centered on incorporating new code into the existing codebase, and typically includes running tests and performing builds. CD focuses on the next logical step, taking the now validated code and generating the necessary outputs to be pushed to the cloud or other destinations. This is probably the most focused upon component of DevOps. |
| 4 | + |
| 5 | +CI/CD fosters a culture of rapid development, collaboration, and continuous improvement, allowing organizations to deliver software updates and new features more reliably and quickly. It ensures consistency, and allows developers to focus on writing code rather than performing manual processes. |
| 6 | + |
| 7 | +[GitHub Actions](https://github.com/features/actions) is an automation platform upon which you can build your CI/CD process. It can also be used to automate other tasks, such as resizing images and validating machine learning models. |
| 8 | + |
| 9 | +## Scenario |
| 10 | + |
| 11 | +A couple of front-end tests have already been defined for the project using [Cypress](https://www.cypress.io/), a popular framework for testing. One of the tests includes checking for the component you'll be adding in a later exercise. To implement CI, you want to run these tests whenever new code is suggested or merged into the **main** branch of the project. |
| 12 | + |
| 13 | +> **IMPORTANT:** Because the test will look for a component you have not yet created, it will fail when it runs for the first time. In an upcoming exercise you will add the code for the test to pass. |
| 14 | +
|
| 15 | +## Exploring the test |
| 16 | + |
| 17 | +Let's take a look at the tests defined for the project. |
| 18 | + |
| 19 | +> **NOTE:** There are only two tests defined for this project. Many projects will have hundreds or thousands of tests to ensure reliability. |
| 20 | +
|
| 21 | +1. Return to your codespace, or reopen it by navigating to your repository and selecting **Code** > **Codespaces** and the name of your codespace. |
| 22 | +1. In **Explorer**, navigate to **src** > **cypress** > **e2e**, and open **app.cy.ts**. |
| 23 | +1. Note the following test, which looks for an element with an id of `hours` and ensures the name of today is displayed: |
| 24 | + |
| 25 | + ```typescript |
| 26 | + it('should display todays day', () => { |
| 27 | + // start from the index page |
| 28 | + cy.visit('http://localhost:3000/') |
| 29 | + |
| 30 | + // get today's long day name |
| 31 | + const today = new Date().toLocaleDateString('en-US', { weekday: 'long' }) |
| 32 | + |
| 33 | + // confirm div with id of hours has today's day |
| 34 | + cy.get('#hours').contains(today) |
| 35 | + }) |
| 36 | + ``` |
| 37 | + |
| 38 | +## Creating the workflow |
| 39 | + |
| 40 | +To run the tests, we'll need to perform a couple of steps. We need to create an environment in which the tests can run, to checkout the code, then run the tests with the appropriate configuration. |
| 41 | + |
| 42 | +As you might expect, performing these types of actions is something numerous organizations need to do as part of their DevOps processes. To support these organizations, there is a [marketplace](https://github.com/marketplace?type=actions) hosted by GitHub containing actions for these and many other tasks. You can then create workflows which build upon these actions. |
| 43 | + |
| 44 | +Workflows are defined as [YAML (or YML)](https://en.wikipedia.org/wiki/YAML) files, and stored as part of the project in a special folder named **.github/workflows**. By being part of the repository, they are subject to the exact same source controls as all other code. It also makes it easier to manage as everything you need is right there in the repository. |
| 45 | + |
| 46 | +Let's create a workflow to implement testing. |
| 47 | + |
| 48 | +1. In the root of your project in the **Explorer** window, navigate to **.github**. |
| 49 | +1. Select the **New Folder** button in the **Explorer** window, and name it **workflows**. |
| 50 | +1. Create a new file in the **workflows** folder by selecting **New File** in the **Explorer** window and name it **e2e.yml**. |
| 51 | +1. In the new file, copy the following YML to create the workflow (we'll describe it in below this step): |
| 52 | + |
| 53 | + ```yml |
| 54 | + name: End-to-end tests |
| 55 | + on: |
| 56 | + push: |
| 57 | + branches: ["main"] |
| 58 | + pull_request: |
| 59 | + branches: ["main"] |
| 60 | + jobs: |
| 61 | + cypress-run: |
| 62 | + runs-on: ubuntu-20.04 |
| 63 | + steps: |
| 64 | + - name: Checkout |
| 65 | + uses: actions/checkout@v3 |
| 66 | + # Install NPM dependencies, cache them correctly |
| 67 | + # and run all Cypress tests |
| 68 | + - name: Cypress run |
| 69 | + uses: cypress-io/github-action@v5 |
| 70 | + with: |
| 71 | + build: npm run build |
| 72 | + start: npm run start |
| 73 | + project: ./source |
| 74 | + env: |
| 75 | + MONGODB_URI: test |
| 76 | + ``` |
| 77 | + |
| 78 | + > **IMPORTANT:** YML is sensitive to tab/space levels. Ensure the tabbing is as displayed above. |
| 79 | + |
| 80 | +### Explaining the workflow |
| 81 | + |
| 82 | +To make this exercise easier, we provided the full YML for the workflow. Let's breakdown what's happening. |
| 83 | + |
| 84 | +- `name`: Provides a name for the workflow, which will display in the logs. |
| 85 | +- `on`: Defines when the workflow will run. In our case, it will run whenever new code is pushed (or merged) into `main`, or a pull request is made to `main`. |
| 86 | +- `jobs`: Defines a series of jobs for this workflow. Each job is considered a unit of work. |
| 87 | + - `runs-on`: Where the operations for the job will be performed. |
| 88 | + - `steps`: The operations to be performed. |
| 89 | + |
| 90 | +The `steps` section is broken down into two steps, each calling an action from the marketplace. The first is [checkout](https://github.com/marketplace/actions/checkout), which as the name implies, checks out your code. The trailing **@v3** pins the version of the action being used. |
| 91 | + |
| 92 | +Next is [Cypress](https://github.com/marketplace/actions/cypress-io), which will run the tests. Note there are a couple of configuration options which need to be set: |
| 93 | + |
| 94 | +- `build`: The build command for the project. |
| 95 | +- `start`: The command to start the website. |
| 96 | +- `project`: The location of the source code so Cypress can find the tests. |
| 97 | +- `MONGODB_URI`: The location of the backend database to use for the project. |
| 98 | + |
| 99 | +> **NOTE:** The application is configured to use [MongoDB In-Memory Server](https://github.com/nodkz/mongodb-memory-server) when `MONGODB_URI` is set to **test**. For sensitive values, you can create [encrypted secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets) for the repository. |
| 100 | + |
| 101 | +## Push the workflow to the repository |
| 102 | + |
| 103 | +With the workflow created, let's push it to the repository. Typically you would create a [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) for any new code (which this is). To streamline the process, we're going to push straight to main as we'll be exploring pull requests and the [GitHub flow](https://docs.github.com/en/get-started/quickstart/github-flow) in a later exercise. You'll start by obtaining the number of the [issue you created earlier](./2-issues.md), creating a commit for the new code, then pushing it to main. |
| 104 | + |
| 105 | +1. Open a terminal window in your codespace by pressing <kbd>Ctl</kbd> + <kbd>`</kbd>. |
| 106 | +1. List all issues for the repository by entering the following command in the terminal window and pressing <kbd>Enter</kbd> (or <kbd>Return</kbd> on a Mac): |
| 107 | +
|
| 108 | + ```bash |
| 109 | + gh issue list |
| 110 | + ``` |
| 111 | +
|
| 112 | +1. Note the issue number for the one titled **Implement testing**. |
| 113 | +1. Stage all files by entering the following command in the terminal window and pressing <kbd>Enter</kbd> (or <kbd>Return</kbd> on a Mac): |
| 114 | +
|
| 115 | + ```bash |
| 116 | + git add . |
| 117 | + ``` |
| 118 | +
|
| 119 | +1. Commit all changes with a message by entering the following command in the terminal window and pressing <kbd>Enter</kbd> (or <kbd>Return</kbd> on a Mac), replacing **<ISSUE_NUMBER>** with the number for the **Implement testing** issue: |
| 120 | +
|
| 121 | + ```bash |
| 122 | + git commit -m "Resolves #<ISSUE_NUMBER>" |
| 123 | + ``` |
| 124 | +
|
| 125 | +1. Push all changes to the repository by entering the following command in the terminal window and pressing <kbd>Enter</kbd> (or <kbd>Return</kbd> on a Mac): |
| 126 | +
|
| 127 | + ```bash |
| 128 | + git push |
| 129 | + ``` |
| 130 | +
|
| 131 | +Congratulations! You've now implemented testing, a core component of continuous integration (CI)! |
| 132 | +
|
| 133 | +## Seeing the workflow in action |
| 134 | +
|
| 135 | +Pushing the workflow definition to the repository counts as a push to `main`, meaning the workflow will be triggered. You can see the workflow in action by navigating to the **Actions** tab in your repository. |
| 136 | +
|
| 137 | +> **IMPORTANT:** The workflow **WILL FAIL** on the first run. This is expected. In the next exercise you will add the code to ensure the test passes. |
| 138 | +
|
| 139 | +1. Return to your repository. |
| 140 | +1. Select the **Actions** tab. |
| 141 | +1. Select the name of the action on the left side. |
| 142 | +1. Note the test running (and eventually failing). You can click the name of the action to see the individual steps, and the logs provided by those steps. |
| 143 | +
|
| 144 | +## Summary and next steps |
| 145 | +
|
| 146 | +Implementing continuous integration and continuous deployment is critical to successful DevOps. Automating these processes ensures consistency and reduces the workload required for developers and administrators. You have created a workflow to run tests on any new code for your codebase. |
| 147 | +
|
| 148 | +Let's turn our attention to [adding code to our project](./5-coding.md). |
| 149 | +
|
| 150 | +### Resources |
0 commit comments