[RUBY] Introduction to RSpec 6. System specifications

Continuation of Last time

What is system spec?

Tests include ** unit tests ** to check if a single model or controller works as expected, such as controller specs or model specs, and to check the behavior of the entire program that integrates multiple models and controllers. There is a ** integration test **.

RSpec provides ** System Spec ** as one of these integration tests. (Similar tests have feature specs, but have been deprecated since Rails 5.1.)

System specs are especially useful as UI tests among integration tests.

Preparation

Install ** Capybara ** to simulate browser operations. You can use it to click links and verify screen display in your tests.

Install Capybara

In Rails 5.0 and later, Capybara is installed by default, so if it is not installed, install it from Gemfile.

group :test do
  gem 'capybara'
end
$ bundle install

Configuration

I will add it to the settings so that I can use the system specifications and Capybara in the test.

spec/rails_helper.rb


#Postscript
require 'capybara/rspec'

RSpec.configre do |config|
  #Postscript
  config.before(:each, type: :system) do
    driven_by :rack_test
  end

  config.before(:each, type: :system, js: true) do
    driven_by :selenium_chrome_headless
  end

Basics of system specifications

Now that the preparations are complete, let's create a spec file first.

$ rails g rspec:system projects

Capybara provides methods such as visit, fill_in, and click_link, so you can easily write scenarios for the functions you need in your app.

spec/features/projects_spec.rb


require 'rails_helper'

RSpec.describe "Projects", type: :system do
  scenario "user creates a new project" do  #The starting point of the same example as it
    user = FactoryBot.create(:user)

    #Login operation
    visit root_path
    click_link "Sign in"
    fill_in "Email", with: user.email
    fill_in "Password", with: user.password
    click_button "Log in"

    #Project creation
    expect {
      click_link "New Project"
      fill_in "Name", with: "Test Project"
      fill_in "Description", with: "Trying out Capybara"
      click_button "Create Project"
      expect(page).to have_content "Project was successfully created"
      expect(page).to have_content "Test Project"
      expect(page).to have_content "Owner: #{user.name}"
    }.to change(user.projects, :count).by(1)
  end
end

The system specs allow you to test similar to what the user does on the browser.

Capybara method

In addition to the above specs, Capybara offers many methods. Among them, I will introduce the ones that appear frequently.

** Open page **

visit "/fake/page"

** Click the link or button label **

click_on "A link or button label"

** Check the label of the checkbox **

check "A checkbox label"

** Uncheck the checkbox label **

uncheck "A checkbox label"

** Select a radio button label **

choose "A radio button label"

** Select an option from the select menu **

select "An option", from: "A select menu"

** Attach the file with the file upload label **

attach_file "A file upload label", "/some/file/in/my/test/suite.f"

** Verify that there is an element that matches the specified CSS **

expect(page).to have_css "h2#subheading"

** Verify that there is an element that matches the specified selector **

expect(page).to have_selector "ul li"

** Verify that the current path is the specified path **

expect(page).to have_current_path "/projects/new"

Ambiguity avoidance

If there are multiple selectors specified on the page and Capybara gets angry with "It's ambiguous", you can solve it by limiting the scope.

#Click the link text with the specified class or id
within "#id or .class" do
  click_link "click here!"
end

#Click the tag with the specified class or id
find('div.class input').click

#Click the first applicable tag on the entire page
first(input).click

#Click the last applicable tag on the entire page
last(input).click

System spec debugging

You can see the test results from the console output, but Capybara uses a headless browser (a browser without a UI) to see the HTML that Rails returns to the browser.

scenario "guest adds a project" do
  visit projects_path
  save_and_open_page  #The HTML returned at this point is saved
  click_link "New Project"
end

HTML is saved by save_and_open_page, so you can check it by opening it in your browser.

This feature is useful, but it's a hassle to open the file manually every time, so install the Launchy gem and let it open automatically.

Gemfile


group :test do
  gem 'launchy'
end
$ bundle install

Testing operations using JavaScript

Preparation

The selenium-webdriver gem installed by default in Rails specifies the JavaScript driver to use for testing, but it seems that there is a compatibility problem with the default FireFox, so change the setting to use Chrome.

I want to separate the Capybara setting file, so I will start with the file reading setting of rails_helper.rb.

spec/rails_helper.rb


Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

spec/support/capybara.rb


Capybara.javascript_driver = :selenium_chrome_headless

In a CI environment, it is not desirable to open a new browser window during the test run, so Capybara allows you to use a ** headless driver ** to meet those needs. Here, I'm setting up to run the test using Chrome's headless mode.

Finally, install the Webdriver gem.

Gemfile


group :test do
  gem 'webdrivers'
end

test

You can test operations using JavaScript by passing the js: true option.

scenario "test name", js: true do
  #Test content
end

JavaScript wait time setting

In Capybara, with the default setting, the waiting time for acquiring the processing result is 2 seconds, but the processing may not be in time and the test may fail. You can optionally set the waiting time to avoid this.

spec/support/capybara.rb


Capybara.default_wait_time = 15 #Set to 15 seconds

This setting applies to the entire test suite, but test execution can be slower than necessary, so it's a good idea to consider using using_wait_time each time you need it.

scenario "test" do
  using_wait_time(15) do  #Waiting time is 15 seconds only in this block
    #Test content
  end
end

Recommended Posts

Introduction to RSpec 6. System specifications
Introduction to RSpec 1. Test, RSpec
Introduction to RSpec 2. RSpec setup
Introduction to RSpec 5. Controller specs
Introduction to RSpec 3. Model specs
Introduction to Ruby processing system self-made
Introduction to Ruby 2
Introduction to SWING
Introduction to web3j
Introduction to Micronaut 1 ~ Introduction ~
[Java] Introduction to Java
Introduction to migration
Introduction to java
Introduction to Doma
Introduction to JAR files
Introduction to Ratpack (8)-Session
Introduction to bit operation
Introduction to Ratpack (6) --Promise
Set RSpec to DRY
Introduction to Ratpack (9) --Thymeleaf
Introduction to PlayFramework 2.7 ① Overview
Introduction to Android Layout
Introduction to design patterns (introduction)
Introduction to Practical Programming
Introduction to javadoc command
Introduction to jar command
Introduction to Ratpack (2)-Architecture
Introduction to lambda expression
Introduction to java command
Introduction to Keycloak development
Introduction to javac command
Introduction to RSpec 4. Create test data with Factory Bot
Introduction to Design Patterns (Builder)
Introduction to Android application development
Introduction to Ratpack (5) --Json & Registry
Introduction to Metabase ~ Environment Construction ~
Introduction to Ratpack (7) --Guice & Spring
(Dot installation) Introduction to Java8_Impression
Introduction to Design Patterns (Composite)
Introduction to Micronaut 2 ~ Unit test ~
Introduction to JUnit (study memo)
Introduction to Spring Boot ① ~ DI ~
Introduction to design patterns (Flyweight)
[Java] Introduction to lambda expressions
Introduction to Spring Boot ② ~ AOP ~
Introduction to Apache Beam (2) ~ ParDo ~
[Ruby] Introduction to Ruby Error statement
Introduction to EHRbase 2-REST API
Introduction to design patterns Prototype
GitHub Actions Introduction to self-made actions
[Java] Introduction to Stream API
Introduction to Design Patterns (Iterator)
Introduction to Spring Boot Part 1
Introduction to Ratpack (1) --What is Ratpack?
External system stub "Subuta" (Introduction)
XVim2 introduction memo to Xcode12.3
Introduction to RSpec-Everyday Rails Summary-
Introduction to Design Patterns (Strategy)
[Introduction to rock-paper-scissors games] Java
Introduction to Linux Container / Docker (Part 1)
Introduction to swift practice output Chapter5