This workshop guides you through setting continuous integration and delivery in a sample React and Node application. You will learn:
- How to setup CI/CD with Heroku Pipelines and Review Apps
- How to write and setup unit and automation tests
- Unit tests with Jest
- Automation tests with Puppeteer and Selenium
- How to setup production monitoring
- Custom uptime/downtime monitoring with Slack notifications
- Error monitoring with Rollbar
- How to keep your dependencies up to date
- Automatic testing dependency upgrades with Greenkeeper
- Checking for security issues with Node Security
The goal is to dip your hands in enough aspects of CI/CD, but not go into depth on any one aspect. This workshop consists mostly of reading and copying and pasting, just like real web development ;)
- Linting
- Continuous Integration
- Storybook
- Code Coverage
- React Tests
- Server Tests
- Continuous Delivery
- Monitoring and Notifications
- End-to-End Tests
- Error Monitoring
- Dependency Upgrades and Security Checks
- GitHub Status Checks
- Dark Launching with Feature Flags
- Learn More
Please read the background below before starting on the lessons.
Contact me:
- GitHub: @jonathanong
- Twitter: @jongleberry
- LinkedIn: @jongleberry
- Email: me@jongleberry.com
The reference app you will be working on and deploying is here: jonathanong/ci-reference-app. This app is based on my personal reference app IMS, so feel free to explore it. If you wish to cheat, there are solutions in the solution branch.
There are a lot of blog posts on this topic. Here is one graph that explains it:
We will be implemented continuous integration and delivery, but not continuous deployment. We will also be implementing a barebones version feature flags. See this post and company for more details:
What is the CI/CD workflow in a few bullet points?
- Deliver small commits often.
- No gigantic PRs, no gigantic merge conflicts
- Dark launch code behind a feature flag so you can ship features without enabling it for all users
- An automated delivery pipeline
- Automatically going to the next step after tests pass
- Automatically triggering jobs when a specific event occurs
- Monitoring in production and elsewhere in your stack to create an automated feedback loop
- Scale your code and team - with sufficient testing, monitoring, and automation, you can be confident that new code works as intended and does not break existing features. Existing CI/CD pipeline will be your guide to your engineering culture.
- Minimize downtime - with sufficient tests and monitors, downtime should be minimal. With sufficient monitors, the time to incident response should be very quick,
- Pinpoint regressions - with small commits and a robust CI/CD pipeline, if a regression even makes it to production, you can easily find the cause.
There's a lot of testing philosophies on the internet. The most common is the testing pyramid:
The latest philosophy, which I prescribe to, in the JS community is the testing trophy:
What do each of these sections mean? It depends on a lot on the context. Here's one breakdown (actual definitions do not matter in real life):
- Static Testing - validate that your code is syntactically correct
- Unit Testing - validate that your components work correctly in isolation
- React examples:
- Shallow snapshot tests
- Testing methods on React components, perhaps with mocking
- Testing that one reducer works correctly
- Server examples:
- Test that a function works correctly
- Test that a single API call returns a valid response
- React examples:
- Integration Testing - validate that your components work correctly together
- React examples:
- Snapshot tests w/ different props
- Testing the entire redux store
- Server examples:
- Test that multiple models interact with each other correctly
- Test that multiple API calls work correctly together
- React examples:
- End-to-End testing:
- Go through a flow on your actual site with a browser
This list is just a guideline, but definitions could change based on your scenario. The main tenets of the testing trophy is:
- Lint!
- Spend time on integration tests instead of unit tests
- Avoid mocking and spying on functions as it takes a lot of effort to write those tests
- Focus on tests that fulfill actual acceptance criteria.
- Unit tests are tests for engineers. End-to-End tests are tests for stakeholders. It's more important to write tests for stakeholders as that's how your work is measured.
- If your tests become too slow, parallelize and shard your tests!
Here is how our custom setup for monitors and automation differ for us at Dollar Shave Club:
Unit / Integration | face-monitor | face-e2e | |
---|---|---|---|
Speed | Fast | Moderate | Slow |
Runs in production | No | Yes | Not Yet |
Runs in staging | No | Yes | Not Yet |
Runs in review apps | No | Yes | Yes |
Supports Selenium | No | No | Yes |
Supports Puppeteer | No | Yes | Yes |
Supports testing all browsers | No | No | Yes |
Supports Sauce Labs | No | No | Yes |
Supports retries | Maybe | Yes | Yes |
Supports retries on Sauce Labs | No | No | Yes |
Supports BDD | Yes | No | Yes |
Flakiness (1-5) | 2 | 3 | 4 |
Hooked up to Datadog and/or alerts | No | Yes | No |
Ability to disable analytics | Yes | Yes | No |
Google Timeline Viewer | No | Yes | No |
Browser Screenshots | Percy Storybook | Implemented | Not Implemented |
face-
are our suites of monitors and e2e tests with a lot of customization involved.
Backend:
Frontend:
Testing:
- eslint
- stylelint
- Jest - for both frontend and backend tests
- supertest - for testing APIs
- Puppeteer - for monitors and automation tests
- Selenium - for automation tests
- @dollarshaveclub/e2e - an end-to-end test runner for Puppeteer and Selenium
- @dollarshaveclub/monitor - a monitoring framework
SaaS:
Install node@8.9
or later:
# If you install via homebrew:
brew install node
# brew upgrade node
# If you install via nvm:
nvm install 8
Install (or upgrade
) Selenium and friends:
brew install selenium-server-standalone chromedriver
# brew upgrade selenium-server-standalone chromedriver
Install Heroku's CLI: https://devcenter.heroku.com/articles/heroku-cli
- We expect you to commit small and often. We won't tell you to
git commit
andgit push
.