Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Use cypress.io or playwright.dev with your rails application. This Ruby gem lets you use your regular Rails test setup and clean-up, such as FactoryBot.

License

NotificationsYou must be signed in to change notification settings

shakacode/cypress-playwright-on-rails

Repository files navigation

Build Statuscypress-on-railsGem Version


This project is sponsored by the software consulting firmShakaCode, creator of theReact on Rails Gem.

ShakaCode Support

ShakaCode focuses on helping Ruby on Rails teams use React and Webpack better. We can upgrade your project and improve your development and customer experiences, allowing you to focus on building new features or fixing bugs instead.

For an overview of working with us, see ourClient Engagement Model article andhow we bill for time.

We also specialize in helping development teams lower infrastructure and CI costs. Check out our projectControl Plane Flow, which can allow you to get the ease of Heroku with the power of Kubernetes and big cost savings.

If you think ShakaCode can help your project,click here to book a call withJustin Gordon, the creator of React on Rails and Shakapacker.

Here's a testimonial of how ShakaCode can help fromFlorian Gößler ofBlinkist, January 2, 2023:

Hey Justin 👋

I just wanted to let you know that we today shipped the webpacker to shakapacker upgrades and it all seems to be running smoothly! Thanks again for all your support and your teams work! 😍

On top of your work, it was now also very easy for me to upgrade Tailwind and include our external node_module based web component library which we were using for our other (more modern) apps already. That work is going to be shipped later this week though as we are polishing the last bits of it. 😉

Have a great 2023 and maybe we get to work together again later in the year! 🙌

Read thefull review here.


Feel free to engage in discussions around this gem at ourSlack Channel or ourforum category for Cypress.

Need help with cypress-on-rails? ContactJustin Gordon.


New to Cypress?

Consider first learning the basics of Cypress before attempting to integrate with Ruby on Rails.

Totally new to Playwright?

Consider first learning the basics of Playwright before attempting to integrate with Ruby on Rails.

Quick Start

# 1. Add to Gemfilegem'cypress-on-rails','~> 1.0'# 2. Install and generatebundle installbin/rails g cypress_on_rails:install# 3. Run tests (new rake tasks!)bin/rails cypress:open# Open Cypress UIbin/rails cypress:run# Run headless

For Playwright:

bin/rails g cypress_on_rails:install --framework playwrightbin/rails playwright:open# Open Playwright UIbin/rails playwright:run# Run headless

Overview

Gem for usingcypress.io orplaywright.dev in Rails and Ruby Rack applications to control state as mentioned inCypress Best Practices.

It allows you to run code in the context of the application when executing Cypress or Playwright tests.Do things like:

  • use database_cleaner before each test
  • seed the database with default data for each test
  • use factory_bot to set up data
  • create scenario files used for specific tests

Has examples of setting up state with:

  • factory_bot
  • rails test fixtures
  • scenarios
  • custom commands

Documentation

📚 Essential Guides

🎥 Resources

Installation

Add this to yourGemfile:

group:test,:developmentdogem'cypress-on-rails','~> 1.0'end

Generate the boilerplate code using:

# by default installs only cypressbin/rails g cypress_on_rails:install# if you have/want a different cypress folder (default is e2e)bin/rails g cypress_on_rails:install --install_folder=spec/cypress# to install playwright instead of cypressbin/rails g cypress_on_rails:install --framework playwright# if you target the Rails server with a path prefix to your URLbin/rails g cypress_on_rails:install --api_prefix=/api# if you want to install with npm insteadbin/rails g cypress_on_rails:install --install_with=npm# if you already have cypress installed globallybin/rails g cypress_on_rails:install --install_with=skip# to update the generated files runbin/rails g cypress_on_rails:install --install_with=skip

The generator creates the following structure in your application:

For Cypress:

e2e/  cypress.config.js              # Cypress configuration  e2e_helper.rb                  # Helper code for factory_bot, database_cleaner, etc.  app_commands/                  # Your custom commands and scenarios    clean.rb    factory_bot.rb    scenarios/      basic.rb  fixtures/    vcr_cassettes/               # VCR recordings (if using VCR)  cypress/    support/      index.js      commands.js      on-rails.js                # Cypress on Rails support code    e2e/      rails_examples/            # Example tests

For Playwright:

e2e/  playwright.config.js           # Playwright configuration  e2e_helper.rb                  # Helper code for factory_bot, database_cleaner, etc.  app_commands/                  # Your custom commands and scenarios (shared with Cypress)  fixtures/    vcr_cassettes/               # VCR recordings (if using VCR)  playwright/    support/      index.js      on-rails.js                # Playwright on Rails support code    e2e/      rails_examples/            # Example tests

Additional files:

  • config/initializers/cypress_on_rails.rb - Configuration for Cypress on Rails

Important: Note thate2e_helper.rb andapp_commands/ are at the root of the install folder (e.g.,e2e/), NOT inside the framework subdirectory (e.g.,e2e/cypress/). This allows both Cypress and Playwright to share the same commands and helpers when using both frameworks.

If you are not usingdatabase_cleaner look ate2e/app_commands/clean.rb.If you are not usingfactory_bot look ate2e/app_commands/factory_bot.rb.

Now you can create scenarios and commands that are plain Ruby files that get loaded through middleware, the ruby sky is your limit.

Update your database.yml

When writing and running tests on your local computer, it's recommended to start your server in development mode so that changes youmake are picked up without having to restart your local server.

It's recommended you update yourdatabase.yml to check if theCYPRESS environment variable is set and switch it to the test databaseotherwise, cypress will keep clearing your development database.

For example:

development:<<:*defaultdatabase:<%= ENV['CYPRESS'] ? 'my_db_test' : 'my_db_development' %>test:<<:*defaultdatabase:my_db_test

WARNING

WARNING!!: cypress-on-rails can execute arbitrary ruby codePlease use with extra caution if starting your local server on 0.0.0.0 or running the gem on a hosted server

Usage

Getting started on your local environment

Using Rake Tasks (Recommended)

The easiest way to run tests is using the provided rake tasks, which automatically manage the Rails server:

# For Cypressbin/rails cypress:open# Opens Cypress test runner UIbin/rails cypress:run# Runs Cypress tests in headless mode# For Playwrightbin/rails playwright:open# Opens Playwright test runner UIbin/rails playwright:run# Runs Playwright tests in headless mode

These tasks will:

  • Start the Rails test server automatically
  • Execute your tests
  • Stop the server when done

Manual Server Management

You can also manage the server manually:

# start railsCYPRESS=1 bin/rails server -p 5017# in separate window start cypressyarn cypress open --project ./e2e# or for npmnpx cypress open --project ./e2e# or for playwrightyarn playwrighttest --ui# or using npmnpx playwrighttest --ui

How to run cypress on CI

# setup rails and start server in background# ...yarn run cypress run --project ./e2e# or for npmnpx cypress run --project ./e2e

Example of using factory bot

You can run yourfactory_bot directly as well

then in Cypress

// spec/cypress/e2e/simple.cy.jsdescribe('My First Test',()=>{it('visit root',()=>{// This calls to the backend to prepare the application statecy.appFactories([['create_list','post',10],['create','post',{title:'Hello World'}],['create','post','with_comments',{title:'Factory_bot Traits here'}]// use traits])// Visit the application under testcy.visit('/')cy.contains('Hello World')// Accessing resultcy.appFactories([['create','invoice',{paid:false}]]).then((records)=>{cy.visit(`/invoices/${records[0].id}`);});})})

then in Playwright

const{ test, expect, request}=require('@playwright/test');test.describe('My First Test',()=>{test('visit root',async({ page})=>{// This calls to the backend to prepare the application stateawaitappFactories([['create_list','post',10],['create','post',{title:'Hello World'}],['create','post','with_comments',{title:'Factory_bot Traits here'}]]);// Visit the application under testawaitpage.goto('/');awaitexpect(page).toHaveText('Hello World');// Accessing resultconstrecords=awaitappFactories([['create','invoice',{paid:false}]]);awaitpage.goto(`/invoices/${records[0].id}`);});});

You can check theassociation docs on more ways to setup association with the correct data.

In some cases, using static Cypress fixtures may not provide sufficient flexibility when mocking HTTP response bodies. It's possible to useFactoryBot.build to generate Ruby hashes that can then be used as mock JSON responses:

FactoryBot.definedofactory:some_web_response,class:Hashdoinitialize_with{attributes.deep_stringify_keys}id{123}name{'Mr Blobby'}occupation{'Evil pink clown'}endendFactoryBot.build(:some_web_response=>{'id'=>123,'name'=>'Mr Blobby','occupation'=>'Evil pink clown'})

This can then be combined with Cypress mocks:

describe('My First Test',()=>{it('visit root',()=>{// This calls to the backend to generate the mocked responsecy.appFactories([['build','some_web_response',{name:'Baby Blobby'}]]).then(([responseBody])=>{cy.intercept('http://some-external-url.com/endpoint',{body:responseBody});// Visit the application under testcy.visit('/')})cy.contains('Hello World')})})

Example of loading Rails test fixtures

# spec/e2e/app_commands/activerecord_fixtures.rbrequire"active_record/fixtures"fixtures_dir=ActiveRecord::Tasks::DatabaseTasks.fixtures_pathfixture_files=Dir["#{fixtures_dir}/**/*.yml"].map{ |f|f[(fixtures_dir.size +1)..-5]}logger.debug"loading fixtures: { dir:#{fixtures_dir}, files:#{fixture_files} }"ActiveRecord::FixtureSet.reset_cacheActiveRecord::FixtureSet.create_fixtures(fixtures_dir,fixture_files)
// spec/cypress/e2e/simple.cy.jsdescribe('My First Test',()=>{it('visit root',()=>{// This calls to the backend to prepare the application statecy.appFixtures()// Visit the application under testcy.visit('/')cy.contains('Hello World')})})

Example of using scenarios

Scenarios are namedbefore blocks that you can reference in your test.

You define a scenario in thespec/e2e/app_commands/scenarios directory:

# spec/cypress/app_commands/scenarios/basic.rbProfile.createname:"Cypress Hill"# or if you have factory_bot enabled in your cypress_helperCypressOnRails::SmartFactoryWrapper.create(:profile,name:"Cypress Hill")

Then reference the scenario in your test:

// spec/cypress/e2e/scenario_example.cy.jsdescribe('My First Test',()=>{it('visit root',()=>{// This calls to the backend to prepare the application statecy.appScenario('basic')cy.visit('/profiles')cy.contains('Cypress Hill')})})

Example of using app commands

Create a Ruby file in thespec/e2e/app_commands directory:

# spec/e2e/app_commands/load_seed.rbload"#{Rails.root}/db/seeds.rb"

Then reference the command in your test withcy.app('load_seed'):

// spec/cypress/e2e/simple.cy.jsdescribe('My First Test',()=>{beforeEach(()=>{cy.app('load_seed')})it('visit root',()=>{cy.visit('/')cy.contains("Seeds")})})

Example of using scenario with Playwright

Scenarios are namedbefore blocks that you can reference in your test.

You define a scenario in thespec/e2e/app_commands/scenarios directory:

# spec/e2e/app_commands/scenarios/basic.rbProfile.createname:"Cypress Hill"# or if you have factory_bot enabled in your cypress_helperCypressOnRails::SmartFactoryWrapper.create(:profile,name:"Cypress Hill")

Then reference the scenario in your test:

// spec/playwright/e2e/scenario_example.spec.jsimport{test,expect}from"@playwright/test";import{app,appScenario}from'../../support/on-rails';test.describe("Rails using scenarios examples",()=>{test.beforeEach(async({ page})=>{awaitapp('clean');});test("setup basic scenario",async({ page})=>{awaitappScenario('basic');awaitpage.goto("/");});});

Experimental Features (matching npm package)

Please test and give feedback.

Add the npm package:

yarn add cypress-on-rails --dev

for VCR

This only works when you start the Rails server with a single worker and single threadIt can be used in two modes:

  • with separate insert/eject calls (more general, recommended way)
  • with use_cassette wrapper (supports only GraphQL integration)

basic setup

Add your VCR configuration to yourconfig/cypress_on_rails.rb

c.vcr_options={hook_into::webmock,default_cassette_options:{record::once},cassette_library_dir:File.expand_path("#{__dir__}/../../e2e/fixtures/vcr_cassettes")}

Add to yourcypress/support/index.js:

import'cypress-on-rails/support/index'

Add to yourcypress/app_commands/clean.rb:

VCR.eject_cassette# make sure we no cassettes inserted before the next test startsVCR.turn_off!WebMock.disable!ifdefined?(WebMock)

insert/eject setup

Add to yourconfig/cypress_on_rails.rb:

c.use_vcr_middleware= !Rails.env.production? &&ENV['CYPRESS'].present?# c.use_vcr_use_cassette_middleware = !Rails.env.production? && ENV['CYPRESS'].present?

insert/eject usage

You havevcr_insert_cassette andvcr_eject_cassette available.https://www.rubydoc.info/github/vcr/vcr/VCR:insert_cassette

describe('My First Test',()=>{beforeEach(()=>{cy.app('load_seed')})it('visit root',()=>{cy.app('clean')// have a look at e2e/app_commands/clean.rbcy.vcr_insert_cassette('cats',{record:"new_episodes"})cy.visit('/using_vcr/index')cy.get('a').contains('Cats').click()cy.contains('Wikipedia has a recording of a cat meowing, because why not?')cy.vcr_eject_cassette()cy.vcr_insert_cassette('cats')cy.visit('/using_vcr/record_cats')cy.contains('Wikipedia has a recording of a cat meowing, because why not?')})})

use_cassette setup

Add to yourconfig/cypress_on_rails.rb:

# c.use_vcr_middleware = !Rails.env.production? && ENV['CYPRESS'].present?c.use_vcr_use_cassette_middleware= !Rails.env.production? &&ENV['CYPRESS'].present?

Adjust record mode inconfig/cypress_on_rails.rb if needed:

c.vcr_options={hook_into::webmock,default_cassette_options:{record::once},}

Add to yourcypress/support/command.js:

// Add proxy-like mock to add operation name into query stringCypress.Commands.add('mockGraphQL',()=>{cy.on('window:before:load',(win)=>{constoriginalFetch=win.fetch;constfetch=(path,options, ...rest)=>{if(options&&options.body){try{constbody=JSON.parse(options.body);if(body.operationName){returnoriginalFetch(`${path}?operation=${body.operationName}`,options, ...rest);}}catch(e){returnoriginalFetch(path,options, ...rest);}}returnoriginalFetch(path,options, ...rest);};cy.stub(win,'fetch',fetch);});});

Add to yourcypress/support/on-rails.js, tobeforeEach:

cy.mockGraphQL()// for GraphQL usage with use_cassette, see cypress/support/commands.rb

use_cassette usage

There is nothing special to be called during the Cypress scenario. Each request is wrapped withVCR.use_cassette.Consider VCR configuration incypress_helper.rb to ignore hosts.

All cassettes will be recorded and saved automatically, using the pattern<vcs_cassettes_path>/graphql/<operation_name>

Server Hooks Configuration

When using the rake tasks (cypress:open,cypress:run,playwright:open,playwright:run), you can configure lifecycle hooks to customize test server behavior:

CypressOnRails.configuredo |c|# Run code before Rails server startsc.before_server_start=->{puts"Preparing test environment..."}# Run code after Rails server is readyc.after_server_start=->{puts"Server is ready for testing!"}# Run code after database transaction begins (transactional mode only)c.after_transaction_start=->{# Load seed data that should be rolled back after tests}# Run code after application state is resetc.after_state_reset=->{Rails.cache.clear}# Run code before Rails server stopsc.before_server_stop=->{puts"Cleaning up test environment..."}# Configure server settingsc.server_host='localhost'# or use ENV['CYPRESS_RAILS_HOST']c.server_port=3001# or use ENV['CYPRESS_RAILS_PORT']c.transactional_server=true# Enable automatic transaction rollbackend

before_request configuration

You may perform any custom action before running a CypressOnRails command, such as authentication, or sending metrics. Please setbefore_request as part of the CypressOnRails configuration.

You should get familiar withRack middlewares.If your function returns a[status, header, body] response, CypressOnRails will halt, and your command will not be executed. To execute the command,before_request should returnnil.

Authenticate CypressOnRails

CypressOnRails.configuredo |c|# ...# Refer to https://www.rubydoc.info/gems/rack/Rack/Request for the `request` argument.c.before_request=lambda{ |request|body=JSON.parse(request.body.string)ifbody['cypress_token'] !=ENV.fetch('SWEEP_CYPRESS_SECRET_TOKEN')# You may also use warden for authentication:#   if !request.env['warden'].authenticate(:secret_key)return[401,{},['unauthorized']]end}end

Send usage metrics

CypressOnRails.configuredo |c|# ...# Refer to https://www.rubydoc.info/gems/rack/Rack/Request for the `request` argument.c.before_request=lambda{ |request|statsd=Datadog::Statsd.new('localhost',8125)statsd.increment('cypress_on_rails.requests')}end

Usage with other rack applications

Add CypressOnRails to your config.ru

# an example config.rurequireFile.expand_path('my_app',File.dirname(__FILE__))require'cypress_on_rails/middleware'CypressOnRails.configuredo |c|c.cypress_folder=File.expand_path("#{__dir__}/test/cypress")enduseCypressOnRails::MiddlewarerunMyApp

add the following file to Cypress

// test/cypress/support/on-rails.js// CypressOnRails: don't remove these commandsCypress.Commands.add('appCommands',(body)=>{cy.request({method:'POST',url:'/__cypress__/command',body:JSON.stringify(body),headers:{'Content-Type':'application/json; charset=utf-8',},log:true,failOnStatusCode:true})});Cypress.Commands.add('app',(name,command_options)=>{cy.appCommands({name:name,options:command_options})});Cypress.Commands.add('appScenario',(name)=>{cy.app('scenarios/'+name)});Cypress.Commands.add('appFactories',(options)=>{cy.app('factory_bot',options)});// CypressOnRails: end// The next is optionalbeforeEach(()=>{cy.app('clean')// have a look at cypress/app_commands/clean.rb});

add the following file to Playwright

// test/playwright/support/on-rails.jsasyncfunctionappCommands(body){constcontext=awaitrequest.newContext();constresponse=awaitcontext.post('/__e2e__/command',{data:body,headers:{'Content-Type':'application/json'}});if(response.status()!==201){constresponseBody=awaitresponse.text();thrownewError(`Expected status 201 but got${response.status()} -${responseBody}`);}returnresponse.json();}asyncfunctionapp(name,commandOptions={}){constbody=awaitappCommands({ name,options:commandOptions});returnbody[0];}asyncfunctionappScenario(name,options={}){constbody={name:`scenarios/${name}`, options};constresult=awaitappCommands(body);returnresult[0];}asyncfunctionappFactories(options){returnapp('factory_bot',options);}asyncfunctionclean(){awaitapp('clean');}

API Prefix

If your Rails server is exposed under a proxy, typicallyhttps://my-local.dev/api, you can use theapi_prefix option.Inconfig/initializers/cypress_on_rails.rb, add this line:

CypressOnRails.configuredo |c|# ...c.api_prefix='/api'end

Contributing

  1. Fork it (https://github.com/shakacode/cypress-on-rails/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Supporters

JetBrainsScoutAPMControl Plane
BrowserStackHoneybadger

The following companies support our open source projects, and ShakaCode uses their products!

About

Use cypress.io or playwright.dev with your rails application. This Ruby gem lets you use your regular Rails test setup and clean-up, such as FactoryBot.

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors36


[8]ページ先頭

©2009-2025 Movatter.jp