DEV Community

Lucas Barret
Lucas Barret

Posted on

A pragmatic guide for Cypress On Rails

I have discovered a wonderful gem, Cypress On Rails, that eases a lot of the process of E2E with Rails App. This incredible gem deserves an article.

Hence through this article, we will navigate through the installation and the basics of the uses of Cypress On Rails.

Let's begin with Cypress On Rails

Let's start a new Rails app and test all this. This will be a simple app where we will store artists.

You can use -T to skip the installation of the default testing gem minitest.

rails new artists_on_rails -T
Enter fullscreen mode Exit fullscreen mode

We can install the FactoryBot, Rspec, and Cypress-On-Rails gems in the dev and test environments.

group :development, :test do
   gem "factory_bot_rails"
   gem "rspec-rails"
     gem "cypress-on-rails"
end
Enter fullscreen mode Exit fullscreen mode

Then we need to install the gem and trigger the boilerplate code generation.

bundle install
//After a while
rails g rspec:install
rails g cypress_on_rails:install 
Enter fullscreen mode Exit fullscreen mode

This will create a folder name Cypress with the following structure :

cypress/
├── app_commands
│   ├── activerecord_fixtures.rb
│   ├── clean.rb
│   ├── eval.rb
│   ├── factory_bot.rb
│   ├── log_fail.rb
│   └── scenarios
│       └── basic.rb
├── cypress_helper.rb
├── e2e
│   └── rails_examples
│       ├── advance_factory_bot.cy.js
│       ├── other.cy.js
│       ├── using_factory_bot.cy.js
│       ├── using_fixtures.cy.js
│       ├── using_scenarios.cy.js
│       └── using_vcr.cy.js
└── support
    ├── commands.js
    ├── index.js
    └── on-rails.js

Six directories, 17 files
Enter fullscreen mode Exit fullscreen mode

Injecting a middleware

When you run the installation of cypress-on-rails a new middleware is injected.
Then every request to your app will pass through this middleware before going to your Application.

If this request comes from Cypress, the middleware will not forward it to your app, and the cypress-on-rails middleware will treat it directly.

rake middleware
use ActionDispatch::HostAuthorization
... a bunch of stuff
use CypressOnRails::Middleware
run ArtOnRails::Application.routes
Enter fullscreen mode Exit fullscreen mode

When you execute some Cypress commands, this will go to a particular endpoint with the prefix /__cypress__/command.

Cypress.Commands.add('appCommands', function (body) {
  Object.keys(body).forEach(key => body[key] === undefined ? delete body[key] : {});
  const log = Cypress.log({ name: "APP", message: body, autoEnd: false })
  return cy.request({
    method: 'POST',
    url: "/__cypress__/command",
    body: JSON.stringify(body),
    log: false,
    failOnStatusCode: false
  }).then((response) => {
    log.end();
    if (response.status !== 201) {
      expect(response.body.message).to.equal('')
      expect(response.status).to.be.equal(201)
    }
    return response.body
  });
});
Enter fullscreen mode Exit fullscreen mode

Then the middleware will intercept the request if it contains this url prefix. This will not be forwarded to the app source.
You can see this in this sample of the code of the lib :

def call(env)
      request = Rack::Request.new(env)
      if request.path.start_with?("#{configuration.api_prefix}/__e2e__/command")
        configuration.tagged_logged { handle_command(request) }
      elsif request.path.start_with?("#{configuration.api_prefix}/__cypress__/command")
        configuration.tagged_logged { handle_command(request) }
        warn "/__cypress__/command is deprecated. Please use the install generator to use /__e2e__/command instead."
      else
        @app.call(env)
      end
end
Enter fullscreen mode Exit fullscreen mode

Seeding

Your E2E tests should not depend on your application's previous state. Then when creating E2E tests, you must populate your database for your specific test case. For example, you can create a rake task to populate your database.

But with Cypress on Rails, you can be much more efficient and develop seeds with Factory Bot. These seeds are called scenarios in CypressOnRails terminology.

Let's generate the model for the artists. Since we have installed the factory bot gem, this will create the factory for our model.

rails g model artists pseudo:string
Enter fullscreen mode Exit fullscreen mode

Now we can modify the basic.rb scenario. And use our factory of artists.

/cypress/appCommands/scenarios/basic.rb
FactoryBot.create(:artist)
Enter fullscreen mode Exit fullscreen mode

Cultural Aside

Jean-Michel Basquiat is a famous artist. He began his career under the pseudo of SAMO with graffiti in the street. And then, he had an incredible career; he was friends with Warhol, even though he died young (at 27).

Populate your database

You can now use the scenarios you have defined in your Cypress test. For example, with the basic seeds, we've modified the following:

describe('Rails using factory bot examples', function() {
  beforeEach(() => {
      //This clean the database
    cy.app('clean') 
    cy.appScenario('basic')
  })
})
Enter fullscreen mode Exit fullscreen mode

You use the new cy.appScenario function, and that's it; when you run your test, the test database will be seeded with your scenario data.

This function is defined in cypress/support/on-rails.js:

Cypress.Commands.add('appScenario', function (name, options = {}) {
  return cy.app('scenarios/' + name, options)
});
Enter fullscreen mode Exit fullscreen mode

This will be based on the previous URL we've seen, /__cypress__/commands. And add /scenarios/basic to it here in our case. This will trigger our seed,

Call the factory directly in your test

You can call a factory directly from your Cypress test when you need to create specific data for a test.
You will use the function cy.appFactories. It takes an array of an array with:
-The method you want to call on the factory (create)
-The factory of the model you want to call (artist)
-The value that we want to provide to the factory ({pseudo:'Jonone'})

it('using single factory bot', function() {
    cy.appFactories([
      ['create', 'artist', {pseudo: 'JonOne'} ]
    ])
  })
Enter fullscreen mode Exit fullscreen mode

With this, you will call the factory directly. The database will be populated with the data you provided to the appFactories method.

Cultural Aside

JonOne is a famous artist. He began his career with graffiti in New York and then came to Paris. Now he is mainstream; he even collaborates with one of the most prominent French retail brands for a marketing campaign.

Conclusion

When you have a stack combining Cypress and Rails, Cypress On Rails is a valuable gem that can ease your E2E test seeding.

Thanks to this gem, you can create seeds called scenarios in Cypress On Rails terminology. These scenarios can use Factory Bot directly, making seeding easier when you have dependencies (not treated in this article).

(PS): TIL that plural of scenario, an Italian word, is scenarii :).

Top comments (2)

Collapse
 
sainig profile image
Gaurav Saini

Nice article!! I myself am learning Cypress for a small project I'm involved with at work. Though it's not in rails, but still I can easily use the concepts demonstrated here.

Thanks

Collapse
 
yet_anotherdev profile image
Lucas Barret

Happy it helps ! :D