A Simple Meteor & CircleCI Setup (August 2019)

August 10, 2019 1:25 pm Published by

In this post we’ll cover a basic continuous integration setup for your Meteor app. The goals are to have CircleCI run your test suite and lint your code every time you push to your GitHub repository. If all the tests pass and there are no linting errors, then CircleCI will deploy your code to Galaxy.

Part 1: Overview

This tutorial assumes a few things:

  • You have a basic knowledge of the Meteor framework
  • You know how to create a repository on GitHub and push code to it.
  • No knowledge of CircleCI required

And for the record, my Meteor & Node stack is:

  • Meteor@1.8.1
  • Node@8.11.4
  • NPM@5.6.0

Part 2: Write some tests

The easiest way to get started with unit tests for Meteor is to create a brand new Meteor app. It will have a client test and a server test included. So let’s do that:

meteor create my-meteor-circle-ci-app
cd my-meteor-circle-ci-app

You will find your tests in /tests/main.js. Now, to run those tests, we need to add the meteortesting:mocha package:

meteor add meteortesting:mocha

For CircleCI to be able to run the client-side tests, we need to use a headless browser. To do that we’ll use the Phantom NPM package:

meteor npm i --save-dev phantomjs-prebuilt

And then we can run our tests in the console by running:

TEST_BROWSER_DRIVER=phantomjs meteor test --once --driver-package meteortesting:mocha

At this point, you should see an output in your console that looks like this:

--------------------------------
----- RUNNING SERVER TESTS -----
--------------------------------

✓ package.json has correct name
✓ server is not client 
2 passing (30ms)

--------------------------------
----- RUNNING CLIENT TESTS -----
--------------------------------

✓ package.json has correct name
✓ client is not server
2 passing (49ms)

All tests finished!

--------------------------------
SERVER FAILURES: 0
CLIENT FAILURES: 0
--------------------------------

If you notice jQuery-related errors when you run this last command, then you can add jQuery to your project by running:

meteor add jquery

Part 3: Set up CircleCI

The first step is to create a CircleCI config file at /.circleci/config.yml and add the following instructions to it:

# Javascript Node CircleCI 2.0 configuration file
# Check https://circleci.com/docs/2.0/language-javascript/ for more details

version: 2
jobs:
  build:
    docker:
      - image: circleci/node:8.11.4
    working_directory: ~/master
    steps:
      - checkout
      - run:
          name: Install Meteor
          command: "curl https://install.meteor.com | /bin/sh"
      - run:
          name: Install NPM dependencies
          command: meteor npm install
      - run:
          name: Install bcrypt
          command: "meteor npm install --save bcrypt"
      - run:
          name: Install PhantomJS
          command: "meteor npm i --save-dev phantomjs-prebuilt"
      - run:
          name: Run unit tests
          command: "TEST_BROWSER_DRIVER=phantomjs meteor test --once --driver-package meteortesting:mocha"
          shell: /bin/sh
workflows:
  version: 2
  Run tests for basic Meteor app:
    jobs:
      - build:
          filters:
            branches:
              only: master

The config file is mostly self-explicit – take a moment to read it line by line and you’ll have a good idea of what each command does.

Commit and push the CircleCI config file to your repo. Then go to your CircleCI account (or create one) and click to “Add Projects > Set Up Project > Start Building”.

CircleCI should spin up an environment and run the test suite. It should take about 60-90 seconds.

Step 4: Add linting

For the sake of simplicity, let’s use the settings recommended in the Meteor guide.

Make sure your package.json file is closed before running the following command as it will write settings.

meteor npm install --save-dev babel-eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-meteor eslint-plugin-react eslint-plugin-jsx-a11y eslint-import-resolver-meteor eslint @meteorjs/eslint-config-meteor

And let’s tweak our Meteor project package.json file – 2 lines inside the scripts object and the esLintConfig lines:

{
  [...]
  "scripts": {
    [...]
    "lint": "eslint .",
    "pretest": "npm run lint --silent"
  },
  "eslintConfig": {
    "extends": "@meteorjs/eslint-config-meteor",
    "env": {
      "meteor": true,
      "node": true,
      "mocha": true
    }
  },
  [...]
}

Now you can run the linter with this command:

meteor npm run lint --silent

If the linter finds errors, they will be displayed in the terminal and the error message are usually very clear and easy to fix. Now is a good time to fix any linting errors you may have.

If no error is found, there will be no output in the terminal.

We can now update our CircleCI config file with the linting command:

[...]

- run:
    name: Lint
    command: "meteor npm run lint --silent"

[...]

So our full `/.circleci/config.yml file at this point will look like this:

# Javascript Node CircleCI 2.0 configuration file
# Check https://circleci.com/docs/2.0/language-javascript/ for more details

version: 2
jobs:
  build:
    docker:
      - image: circleci/node:8.11.4
    working_directory: ~/master
    steps:
      - checkout
      - run:
          name: Install Meteor
          command: "curl https://install.meteor.com | /bin/sh"
      - run:
          name: Install NPM dependencies
          command: meteor npm install
      - run:
          name: Install bcrypt
          command: "meteor npm install --save bcrypt"
      - run:
          name: Lint
          command: "meteor npm run lint --silent"
      - run:
          name: Install PhantomJS
          command: "meteor npm i --save-dev phantomjs-prebuilt"
      - run:
          name: Run unit tests
          command: "TEST_BROWSER_DRIVER=phantomjs meteor test --once --driver-package meteortesting:mocha"
          shell: /bin/sh
workflows:
  version: 2
  Run tests for basic Meteor app:
    jobs:
      - build:
          filters:
            branches:
              only: master

Now you can commit and push your code. It will automatically trigger CircleCI, which will spin up an environment, lint your code and run the test suite. The process should take about 60-90 seconds. Check your CircleCI account to follow the progress.

Part 5: Deploy automatically to Galaxy Hosting

If you don’t already have Meteor Developer & Galaxy accounts, set those up first.

Generate a deployment token by running this command:

METEOR_SESSION_FILE=deployment_token.json meteor login

That command will create a file in your Meteor project that will allow you to deploy directly from Circle CI.

You will also need a settings file to deploy to Galaxy. Here’s the simplest /settings.json file possible:

{
  "galaxy.meteor.com": {
    "env": {
      "ROOT_URL": "http://YOUR_APP_NAME_GOES_HERE.meteorapp.com"
    }
  }
}

And we need to set 2 environments variables for the meteor deploy command.

I opted to use the Circle CI GUI to set environment variables because it’s simple and it works! In the Circle CI GU go to:

Project settings > Environment Variables

Add 2 environment variables:

DEPLOY_HOSTNAME
us-east-1.galaxy-deploy.meteor.com

METEOR_SESSION_FILE
deployment_token.json

And tack on a few lines at the end of your /.circleci/config.yml file:

[...]

      - run:
          name: Deploy to Galaxy
          command: "meteor deploy YOUR_APP_NAME_GOES_HERE.meteorapp.com --settings settings.json"
          no_output_timeout: "20m"

[...]

So our full ./circleci/config.yml file looks like this:

# Javascript Node CircleCI 2.0 configuration file
# Check https://circleci.com/docs/2.0/language-javascript/ for more details

version: 2
jobs:
  build:
    docker:
      - image: circleci/node:8.11.4
    working_directory: ~/master
    steps:
      - checkout
      - run:
          name: Install Meteor
          command: "curl https://install.meteor.com | /bin/sh"
      - run:
          name: Install NPM dependencies
          command: meteor npm install
      - run:
          name: Install bcrypt
          command: "meteor npm install --save bcrypt"
      - run:
          name: Lint
          command: "meteor npm run lint --silent"
      - run:
          name: Install PhantomJS
          command: "meteor npm i --save-dev phantomjs-prebuilt"
      - run:
          name: Run unit tests
          command: "TEST_BROWSER_DRIVER=phantomjs meteor test --once --driver-package meteortesting:mocha"
          shell: /bin/sh
      - run:
          name: Deploy to Galaxy
          command: "meteor deploy YOUR_APP_NAME_GOES_HERE.meteorapp.com --settings settings.json"
          no_output_timeout: "20m"

workflows:
  version: 2
  Run tests for basic Meteor app:
    jobs:
      - build:
          filters:
            branches:
              only: master

Step 6: The Final Touch

Let’s add the cool “passing badge” from CircleCI on our Github repo.

Create a /readme.md file for your project:

![Circle CI](https://circleci.com/gh/YOUR_GITHUB_USERNAME_GOES_HERE/YOUR_REPO_NAME_GOES_HERE.svg?style=shield&circle-token=:circle-token)

# My Meteor app with continuous integration and automatic deployment

Now push all changes to your repo.

You can track the build process on Circle CI. This setup takes about 1 or 2 minutes to build on Circle CI and another minute or so for Galaxy to deploy.

If you app passes the linting and the unit tests, you can now view your app online at YOUR_APP_NAME_GOES_HERE.meteorapp.com

And check out that beautiful “passing” badge on Github! Yeah!


Resources

Github repo with code from this tutorial

Circle CI

Galaxy hosting

Meteor Guide: Testing

Meteor Guide: Linting

About the author

I’ve been following Meteor since v0.3 and started building production apps since v1.0. I’m CTO at Tripidee in Hawaii. If you’d like to work on cutting-edge Meteor and Cordova projects, email me at yacine@tripidee.com . We always need help.

Aloha.

Categorised in: ,

This post was written by Yacine