Using Cypress with Rails 6

Ali Erbay
4 min readJul 31, 2020

--

End-to-end (E2E) or Integration testing is a technique that tests the entire software product from beginning to end to ensure the application flow behaves as expected. In other words, it helps define the product system dependencies and ensures all integrated pieces work together as expected. Eventually, the main purpose of this testing type is to test from the end user’s experience by simulating the real user scenario and validating the system under test and its components for integration and data integrity.

Photo by Sophie Dale on Unsplash

By default, Rails uses Selenium WebDriver for e2e testing. Selenium is a library but requires a unit testing framework or a runner plus an assertions library to build out its capabilities. It works hand in hand with Capybara and Nokogiri, but thanks to Rails, we don’t need to setup Selenium, it comes ready to use with your Rails stack app.

I use Cypress for end-to-end testing for my React applications. Cypress provides a robust, complete framework for running automated tests and Cypress tests are written using Mocha and Chai so the syntax will be very familiar with JavaScript users.

I decided to use Cypress with a Rails full-stack application. But there were some issues I needed to solve first. We will investigate them as I set-up for Cypress end-to-end testing

Adding Cypress to the application

Let’s start adding Cypress and Axios to our full-stack Rails App;

Right after installing Cypress, we can add a script at the end of our package.json file to run Cypress easily, my package.json file looks like below;

If you type yarn cypress:open on your terminal now, you can start up your Cypress for the first time.

Adding seed file to populate the test database

I prefer to run every test in Test environment, so my db/seeds.rb file will include the following;

In my React application tests, I stub out RESTful API calls and simulate my HTTP requests to backend API which is in most cases a Rails API. In this case, I can’t really stub any network calls because front-end and back-end are in the same stack. So we need to have a way to delete the test database after each test runs.

Resetting the test database between tests

We need a controller and an endpoint to make changes to our test database, in this case, seeding and resetting it.

I have added an endpoint to config/routes.rb file;

test/reset_database endpoint will send POST requests to the database controller’s reset_database action.

Next step should be creating the database controller ( For simplicity, I have skipped controller spec for this controller ) app/controllers/test/databases_controller.rb

Lines 6 and 7 are important here, I’m using Rails default database SQLite in this app, so in order to reset auto-incremented row ID’s when I try to reset all database I needed to delete sqlite_sequence meta table also. But If I had used PostgreSQL, line 6 and 7 could be replaced by the following line;

ActiveRecord::Base.connection.execute("TRUNCATE #{table}")

So now we have a way to delete and seed our test database, we will use this newly created endpoint with Cypress in the test environment. To run Rails app in the test environment we need to type RAILS_ENV=test rails s in the terminal.

Note: You may need to run rails db:test:preparebefore you run your server. Otherwise, it will fail to seed the database.

Setting up Cypress commands

Our endpoint and controller for the database is ready, now we need to write helpers for Cypress to delete and seed databases in test files. In order to do that, we can use the already created cypress/support/command.js file. We are going to make use of Axios package here

There is one more thing we need to adjust in our Rails application, since Cypress HTTP requests will come from another origin ( not localhost:3000 ), we need to configure CORS for allowing these requests. Add gem called rack-cors to the gemfile, if you haven’t got it. Then you need to add this configuration to config/application.rb file,

So, how would our test file look like? We have created two helpers for Cypress named deleteDatabase and deleteAndSeedDatabase

In this way, our test database will be deleted and re-seeded after each example test, making sure that we are not continuously filling our test database after each test we run and avoid duplicates that may cause false-positive results.

Conclusion

If we want to test our Rails app with Cypress, we can’t use FactoryBot or transactional fixtures to accomplish two steps of the Four-Phase test(setup-exercise-verify-teardown) as we are able to do with RSpec/Selenium tests. So we had to improvise to take responsibility for our test database to behave in a transactional way.

If you are looking for more robust way to use Cypress with Rails you can check the gem called cypress-on-rails, I haven’t tried it yet but I’m sure it covers much more than the content of this article

--

--

Ali Erbay

Full Stack Developer BDD/TDD || Ruby on Rails || React || React Native || NodeJS || Express https://github.com/kermit-klein