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.
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 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
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 )
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;
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
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.
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