Cypress is an amazing tool for end to end testing Rails applications, but large test suites can quickly take upwards of 20 minutes to run. That’s where Knapsack Pro comes in. Knapsack Pro Queue Mode to intelligently split your test suite into jobs that can be run in parallel , reducing run time to only a few minutes. In this article we’ll show how to quickly implement Knapsack Pro Queue Mode to speed up both Cypress & RSpec test suites in a Ruby on Rails app on Github Actions
Set up Knapsack Pro API Keys
First step is to go to your Knapsack dashboard and grab your API keys for both RSpec and Cypress. Once you have those, go to your Github Repo’s settings, for example:
Set up your GitHub Actions config file
Once you’ve added your KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC
and KNAPSACK_PRO_TEST_SUITE_TOKEN_CYPRESS
secrets, the next step is setting up your GitHub Actions configuration file to use the Knapsack Runner in place of the normal commands to run RSpec and Cypress.
Existing GitHub Actions config
For those that already have a GH actions config file setup (e.g. .github/workflows/ci.yml
), here’s all that you should need to change to get Knapsack Pro Queue Mode working for both Cypress and RSpec.
Change your RSpec run command to use Knapsack:
+ strategy:
+ fail-fast: false
+ matrix:
+ # Set N number of parallel jobs you want to run tests on.
+ # Use higher number if you have slow tests to split them on more parallel jobs.
+ # Remember to update ci_node_index below to 0..N-1
+ ci_node_total: [2]
+ # set N-1 indexes for parallel jobs
+ # When you run 2 parallel jobs then first job will have index 0, the second job will have index 1 etc
+ ci_node_index: [0, 1]
- name: Run RSpec Tests
+ env:
+ KNAPSACK_PRO_CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
+ KNAPSACK_PRO_CI_NODE_INDEX: ${{ matrix.ci_node_index }}
+ KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC: ${{ secrets.KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC }}
+ KNAPSACK_PRO_FIXED_QUEUE_SPLIT: true
+ run: bin/rake knapsack_pro:queue:rspec # Run RSpec using Knapsack Pro Queue Mode
- run: bin/rspec spec
Change your cypress run command to use Knapsack as well:
+ strategy:
+ fail-fast: false
+ matrix:
+ ci_node_total: [5]
+ # set N-1 indexes for parallel jobs
+ # When you run 2 parallel jobs then first job will have index 0, the second job will have index 1 etc
+ ci_node_index: [0, 1, 2, 3, 4]
- name: Run cypress tests
+ env:
+ KNAPSACK_PRO_TEST_SUITE_TOKEN_CYPRESS: ${{ secrets.KNAPSACK_PRO_TEST_SUITE_TOKEN_CYPRESS }}
+ KNAPSACK_PRO_CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
+ KNAPSACK_PRO_CI_NODE_INDEX: ${{ matrix.ci_node_index }}
+ KNAPSACK_PRO_FIXED_QUEUE_SPLIT: true
+ KNAPSACK_PRO_TEST_FILE_PATTERN: '{cypress/**/*,app/javascript/**/*.component}.spec.{js,ts,tsx}'
+ run: yarn knapsack-pro-cypress
- run: yarn cypress run
New Github Actions config file
For those starting from scratch, here’s a full example .github/workflows/ci.yaml
for a Rails app with Cypress + RSpec with Knapsack tokens for RSpec and Cypress already added.
name : ci
on : [ push ]
jobs :
# OPTIONAL: Cancel any previous CI runs to save your GH Actions minutes
cancel :
name : " Cancel Previous Runs"
runs-on : ubuntu-20.04
timeout-minutes : 3
steps :
- uses : styfle/cancel-workflow-action@0.8.0
with :
workflow_id : 3553203
yarn :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v2
- uses : actions/setup-node@v2-beta
with :
node-version : " 12"
- uses : actions/cache@v2
with :
path : " **/node_modules"
key : ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
restore-keys : |
${{ runner.os }}-yarn-
- name : Yarn install
run : yarn install --frozen-lockfile
env :
CYPRESS_INSTALL_BINARY : 0 # Prevent installing Cypress binary until later when it's needed
bundle :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v2
- uses : ruby/setup-ruby@v1
with :
bundler-cache : true
rspec :
timeout-minutes : 3 # Adjust as needed, just here to prevent accidentally using up all your minutes from a silly infinite loop of some kind
env :
RAILS_ENV : test
runs-on : ubuntu-latest
needs : [ bundle ]
strategy :
fail-fast : false
matrix :
# Set N number of parallel jobs you want to run tests on.
# Use higher number if you have slow tests to split them on more parallel jobs.
# Remember to update ci_node_index below to 0..N-1
ci_node_total : [ 2 ]
# set N-1 indexes for parallel jobs
# When you run 2 parallel jobs then first job will have index 0, the second job will have index 1 etc
ci_node_index : [ 0 , 1 ]
steps :
- uses : actions/checkout@v2
- uses : ruby/setup-ruby@v1
with :
bundler-cache : true
- name : Build DB
run : bin/rails db:schema:load
- name : Run RSpec Tests
env :
PGPORT : ${{ job.services.postgres.ports[5432] }} # get randomly assigned published port
KNAPSACK_PRO_CI_NODE_TOTAL : ${{ matrix.ci_node_total }}
KNAPSACK_PRO_CI_NODE_INDEX : ${{ matrix.ci_node_index }}
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC : ${{ secrets.KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC }}
KNAPSACK_PRO_FIXED_QUEUE_SPLIT : true
run : bin/rake knapsack_pro:queue:rspec # Run RSpec using Knapsack Pro Queue Mode
cypress :
timeout-minutes : 20 # Adjust as needed, just here to prevent accidentally using up all your minutes from a silly infinite loop of some kind
env :
RAILS_ENV : test
RACK_ENV : test
GITHUB_TOKEN : ${{ github.token }}
runs-on : ubuntu-latest
needs : [ bundle , yarn ]
strategy :
fail-fast : false
matrix :
ci_node_total : [ 5 ]
# set N-1 indexes for parallel jobs
# When you run 5 parallel jobs then first job will have index 0, the second job will have index 1 etc
ci_node_index : [ 0 , 1 , 2 , 3 , 4 ]
steps :
- uses : actions/checkout@v2
- uses : actions/setup-node@v2-beta
with :
node-version : " 12"
- uses : actions/cache@v2
with :
path : " **/node_modules"
key : ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
- uses : ruby/setup-ruby@v1
with :
bundler-cache : true
- name : Build DB
run : bin/rails db:schema:load
- name : Run Rails Server in background
run : bin/rails server -p 3000 &
- run : npx cypress -v > .cypress-version
- uses : actions/cache@v2
with :
path : ~/.cache/Cypress
key : cypress-cache-v3-${{ runner.os }}-${{ hashFiles('.cypress-version') }}
- run : yarn cypress install
- uses : actions/setup-node@v2-beta
with :
node-version : " 12"
- run : yarn wait-on 'http-get://localhost:3000' -t 30000
- name : Run tests
env :
KNAPSACK_PRO_TEST_SUITE_TOKEN_CYPRESS : ${{ secrets.KNAPSACK_PRO_TEST_SUITE_TOKEN_CYPRESS }}
KNAPSACK_PRO_CI_NODE_TOTAL : ${{ matrix.ci_node_total }}
KNAPSACK_PRO_CI_NODE_INDEX : ${{ matrix.ci_node_index }}
KNAPSACK_PRO_FIXED_QUEUE_SPLIT : true
KNAPSACK_PRO_TEST_FILE_PATTERN : " {cypress/**/*,app/javascript/**/*.component}.spec.{js,ts,tsx}"
run : yarn knapsack-pro-cypress # Run Cypress using Knapsack Pro Queue Mode
# Save screenshots and videos of failed tests and make them available as Github build artifacts
- uses : actions/upload-artifact@v2
if : failure()
with :
name : cypress-screenshots
path : cypress/screenshots
- uses : actions/upload-artifact@v2
if : failure()
with :
name : cypress-videos
path : cypress/videos
- uses : actions/upload-artifact@v2
if : failure()
with :
name : cypress-logs
path : cypress/logs
Add Knapsack Pro gem and npm package
Add the Knapsack Pro gem to your Gemfile
:
group :development , :test do
#...
gem 'knapsack_pro'
end
Add the Knapsack Pro npm package with yarn add --dev @knapsack-pro/cypress
Run your tests & view your results
Once you’ve completed the above steps, trigger a test run on your repo. You should see multiple jobs for both RSpec and Cypress like so:
Now check your Knapsack Dashboard for the results 🚀
The complete example Rails app can be found here . Happy testing!