visit
Our Sample Project
Now let's look at our sample project and deployment setup. For this project, we’ll be using GitHub as our repository, Heroku as our host, and CircleCI as our CI/CD tool. Heroku is a PaaS solution that makes it easy to deploy and manage apps. CircleCI provides cloud-based CI/CD, running automated jobs in containers as soon as project code is pushed to GitHub. These jobs perform tests, send success or failure notifications, and then deploy built applications to cloud service environments.In the end, we want our outcome to be: When we push our master branch to GitHub, an automated process will run all of our tests and then (if all the tests pass) deploy the application to Heroku.
To that end, I'll take you through the following steps:
Set up a GitHub repository.Create a basic NuxtJS application.Write a few tests for our application.Manually deploy the NuxtJS application to Heroku.Configure CircleCI to run our test suite upon push to GitHub.Configure CircleCI to deploy our application to Heroku upon passing tests.Sound pretty simple? It will be. Let’s go!Choose any name you’d like for this private repository. For this tutorial, we will call our repository
my-heroku-nuxt-app
.Click on “Create repository” to finish up. Then, clone the repository on your local machine. In the command below, make sure to use your own GitHub username. Notice that we are cloning the empty repository into a folder called
app
.~/$ git clone [email protected]:[GITHUB USERNAME]/my-heroku-nuxt-app.git app
Cloning into 'my-heroku-nuxt-app'...
warning: You appear to have cloned an empty repository.
~/app$ yarn create nuxt-app
create-nuxt-app v3.0.0
✨ Generating Nuxt.js project in .
? Project name my-heroku-nuxt-app
? Choose programming language JavaScript
? Choose the package manager Yarn
? Choose UI framework None
? Choose Nuxt.js modules None
? Choose linting tools None
? Choose test framework Jest
? Choose rendering mode Universal (SSR / Static)
? Choose development tools None
By the way, if you would like to use
npm
instead of yarn
, you can use the command npx create-nuxt-app
instead of the yarn create
command above.Verify that your application works by running
yarn dev
from the command line. Your browser window should look like the following:We’ll write tests just for our
index
page. Keep in mind that we are not planning to build anything beyond this basic boilerplate NuxtJS application. Our goal is to learn how to automate testing and deployment to Heroku.For testing, we'll use , which is a popular JavaScript testing framework. It's easy to use and lightning fast. When we created our NuxtJS application above, we opted to bundle in Jest.In the
app/pages
folder, create a new test file called index.test.js
. We will write three tests which verify that our index
page has certain content.// FILE: ~/app/pages/index.test.js
import { mount } from '@vue/test-utils'
import index from './index.vue'
describe('index page', () => {
const wrapper = mount(index)
describe('app title', () => {
const element = wrapper.find('.title')
it('displays app title', () => {
expect(element.text()).toEqual('my-heroku-nuxt-app')
})
})
describe('links', () => {
const links = wrapper.find('.links')
describe('nuxtjs', () => {
it('contains link with correct text', () => {
const link = links.find('[href="//nuxtjs.org/"]')
expect(link.text()).toEqual('Documentation')
})
})
describe('github', () => {
it('contains link with correct text', () => {
const link = links.find('[href="//github.com/nuxt/nuxt.js"]')
expect(link.text()).toEqual('GitHub')
})
})
})
})
Let’s run our tests. We won’t be concerned about test coverage, so let’s include the -
-coverage false flag
.~/app$ yarn test --coverage false
PASS pages/index.test.js
index page
app title
✓ displays app title (3 ms)
links
nuxtjs
✓ contains link with correct text (1 ms)
github
✓ contains link with correct text (1 ms)Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 1.405 s, estimated 2 s
Ran all test suites.
Done in 2.21s.
~/app$ git add .
~/app$ git commit -m "Create nuxt app with tests."
~/app$ git push origin
Nicely done. Now, we have a NuxtJS application with a few tests (which are passing), and we’ve pushed our
master
branch to GitHub.Choose a name for your application. For this tutorial, we’ll go with the same name that we’ve been using thus far. Note that app names on Heroku must be unique across their system. So, it’s possible that
my-heroku-nuxt-app
is not available. If that’s the case, choose another name and take note of that for substitution as we go through this tutorial.~/app$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to //cli-auth.heroku.com/auth/cli/browser/ ...
Logging in... done
Logged in...
Since our GitHub repository for this project already exists, we want to add the new Heroku remote. Make sure to use the Heroku application name that you chose above, if
my-heroku-nuxt-app
wasn’t available.~/app$ heroku git:remote -a my-heroku-nuxt-app
~/app$ heroku config:set HOST=0.0.0.0
~/app$ heroku config:set NODE_ENV=production
~/app$ git push heroku
Enumerating objects: 17, done.
Counting objects: 100% (17/17), done.
Delta compression using up to 4 threads
Compressing objects: 100% (14/14), done.
Writing objects: 100% (17/17), 167.78 KiB | 5.99 MiB/s, done.
Total 17 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Compressing source files... done.
remote: Building source:
remote: -----> Node.js app detected
remote: -----> Creating runtime environment
remote: -----> Installing binaries
remote: -----> Installing dependencies
remote: -----> Build
remote: -----> Pruning devDependencies
remote: -----> Caching build
remote: -----> Build succeeded!
remote: -----> Discovering process types
remote: -----> Compressing...
remote: -----> Launching...
remote: //my-heroku-nuxt-app.herokuapp.com/ deployed to Heroku
remote: Verifying deploy... done.
The command above is where all of the magic happens. Heroku detects that this is a Node.js app, and then it creates the proper deployment environment and installs all dependencies. After installing dependencies, Heroku also runs the
build
script command found in your package.json
— this bundles all of the files needed for the client and for the server.When we visit the URL for our Heroku app, we see our NuxtJS application up and running on the web:From the CircleCI projects dashboard, you will see your GitHub repository named
my-heroku-nuxt-app
— click on the “Set Up Project” button to its right.We’re told that we will need to create a
.circleci
sub-folder in our repository root folder, and then add a config.yml
to that sub-folder. That’s what we’re about to do. We don’t need to download the template config.yml
file, since we’re going to write our own. So, just click on “Start Building”.CircleCI will immediately execute a workflow for this project. You’ll notice that this first build attempt fails. That’s because CircleCI is looking for the
config.yml
file in the .circleci
sub-folder of the master
branch of your project repository. That file doesn't exist yet, so let's create it now.In your project root folder, create a new sub-folder called
.circleci
:~/app$ mkdir .circleci
In that folder, create a new file named
config.yml
. We’re going to break this part of the tutorial into two separate parts. First, we’ll configure CircleCI to run our tests. Then, after we get that up and running, we’ll move on to configuring for Heroku deployment.The contents of
config.yml
should be the following:// FILE: ~/app/.circleci/config.yml
version: 2.1
jobs:
run-test-suite:
docker:
- image: circleci/node:10.20.0
working_directory: ~/project
steps:
- checkout
- run:
name: Fetch dependencies
command: yarn install --no-progress --non-interactive --silent --pure-lockfile
- run:
name: Run test suite
command: yarn test_ci
- persist_to_workspace:
root: ~/project
paths:
- .
workflows:
test-and-deploy:
jobs:
- run-test-suite
run-test-suite
.yarn test_ci
, and then saves the current workspace folder to the machine, so that other jobs can still access the contents in its current state.test-and-deploy
, only has one job in it: run-test-suite
.You may have noticed that CircleCI will call
yarn test_ci
from within our project folder to run the test suite. But we haven’t defined test_ci
in our package.json
script commands yet. We'll define that command with an . This affects how Jest handles . Though we don't have any of those in our project right now, you'll want to keep this in mind in case you write snapshot tests for your projects in the future.. Since we’re updating our package.json
file, let’s also turn off code coverage testing when running Jest:// Excerpt from FILE: ~/app/package.json
...
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"test": "jest --coverage false",
"test_ci": "yarn test --ci"
},
...
Now, let’s add our new
.circleci/config.yml
file and our updated package.json
file to git staging, and then commit them.~/app$ git add .
~/app$ git commit -m "Add CircleCI config for testing, update package.json"
We push our new commit to
master
:~/app$ git push origin
Within a few seconds, you should see a new pipeline entry on your CircleCI dashboard for this project. The
test-and-deploy
workflow for your project, on the master
branch, will begin executing. It will execute the first and only job, which is to run-test-suite
. Our tests should pass, and everything should be green.To do this, we need to modify our
config.yml
file with the CircleCI configuration. We will make use of CircleCI’s . CircleCI Orbs are reusable packages used to simplify configuration. CircleCI has a which simplify integration with third-party technologies (like Heroku). Our updated config.yml
should look like the following (changes in bold):// FILE: ~/app/.circleci/config.yml
version: 2.1
orbs:
heroku: circleci/[email protected]
jobs:
run-test-suite:
docker:
- image: circleci/node:10.20.0
working_directory: ~/project
steps:
- checkout
- run:
name: Fetch dependencies
command: yarn install --no-progress --non-interactive --silent --pure-lockfile
- run:
name: Run test suite
command: yarn test_ci
- persist_to_workspace:
root: ~/project
paths:
- .
deploy-to-heroku:
docker:
- image: circleci/node:10.20.0
working_directory: ~/project
steps:
- attach_workspace:
at: ~/project
- heroku/deploy-via-git
workflows:
test-and-deploy:
jobs:
- run-test-suite
- deploy-to-heroku:
requires:
- run-test-suite
filters:
branches:
only: master
run-test-suite
job, we now have a deploy-to-heroku
job. It also uses the same Node.js version and working directory.deploy-to-heroku
job has two steps: First, it attaches to the workspace which we persisted in the previous job. Second, it calls the deploy-via-git
command, which is defined in CircleCI’s Heroku orb. Essentially, it runs a Heroku CLI command similar to what we did when we manually deployed our application to Heroku above.deploy-to-heroku
job to our test-and-deploy workflow, but we put some constraints on this job. First, it will only run after a successful run of the run-test-suite
job. Also, it will only run if CircleCI is responding to a webhook for the master
branch from our GitHub repository. This means that all branches pushed to GitHub will result in a run of the run-test-suite
job. But, only the master
branch will continue on with the deploy-to-heroku job. This make sense because we would, of course, only want to deploy the master
branch to production.We need to add two environment variables. The first is
HEROKU_API_KEY
, which can be found at your Heroku account settings.Click on “Reveal” and then copy/paste that value over in CircleCI as the value for the
HEROKU_API_KEY
environment variable.The second environment variable we need in CircleCI is
HEROKU_APP_NAME
, which is the name of the Heroku app that you established when creating the app. (For our tutorial, it’s my-heroku-nuxt-app
.)After adding these two environment variables, your CircleCI project settings should look similar to below:Now that we’re all set, we can stage and commit our updated
.circleci/config.yml
file to git, then push to GitHub:~/app$ git add .
~/app$ git commit -m "Update CircleCI config for Heroku deployment"
~/app$ git push origin
master
branch is pushed to GitHub.test-and-deploy
workflow for this project.run-test-suite
. All of the tests run and they all pass.deploy-to-heroku
job runs next, since run-test-suite
succeeded and the branch that just got a new commit is master
.HEROKU_API_KEY
environment variable (which gives CircleCI authorization to access your Heroku apps) and the HEROKU_APP_NAME
environment variable (which lets CircleCI know which Heroku app to deploy), the job pushes the code to Heroku.yarn create nuxt-app
.We wrote tests for our NuxtJS application, using Jest.master
branch to GitHub and all of the tests pass.