I write tests using Minitest and routinely reference EvilMartians System of a Test blog post for best practices for system tests. In this blog post, they also have an opinionated way of setting up System Tests.
EvilSystems
offers 3 distinct advantages over the setup provided by
EvilMartians System of a Test:
1.) The blog post was built with RSpec in mind, but we use Minitest here!
2.) Constantly copying 5 files over into every new Rails app is annoying. Lets make that easier!
3.) File changes can end up out of sync, a gem makes sure updates can be pushed to all users.
EvilSystems
is a quick, easy, reusable way to apply the SoaT concepts and settings
to projects for system tests using Minitest.
Full API documentation can be found here:
https://rdoc.info/github/paramagicdev/evil_systems/main
bundle add evil_systems --group=test
Make sure the following 3 gems are in your Gemfile
as well:
# Gemfile
group :test do
gem 'capybara'
gem 'cuprite' # Optional
gem 'selenium-webdriver' # Not required if using Cuprite and using Rails >= 6.1
end
Note:
bundle add
by default appends the gem to the bottom of yourGemfile
, which means not in thetest
group of gems. If thecapybara
gem is in thetest
group, butevil_systems
is not, you will not be able to load your application in production. Be sure thatevil_systems
is placed in the same group ascapybara
(we recommend thetest
group).
Navigate to test/application_system_test_case.rb
in your Rails app.
Setup your file like so:
# test/application_system_test_case.rb
require 'test_helper'
# 'capybara' and 'capybara/cuprite' need to be defined for EvilSystems to work properly.
require 'capybara'
require 'capybara/cuprite'
require 'evil_systems'
EvilSystems.initial_setup
# To pass in driver_options to cuprite you can do the following:
# EvilSystems.initial_setup(driver_options: { process_timeout: 20 })
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :evil_cuprite
include EvilSystems::Helpers
end
Maybe in the future?
EvilSystems.initial_setup
takes three keyword arguments, :task
, and
silent
, skip_task
.
They all have to do with precompiling assets.
:silent
by default is set to true
and will only tell you when assets
are compiling, and how long the compilation took.
:task
defaults to assets:precompile
, System of a test uses
webpacker:compile
.
:skip_task
when true
says you dont want to run any Rake tasks. Default is false
Example:
EvilSystems.initial_setup(task: "webpacker:compile", silent: false)
-
- Automatically registers a
:evil_cuprite
driver ifCapybara::Cuprite
is defined. -
- Automatically sets Capybara's default and javascript driver to
:evil_cuprite
-
- Automatically sets
Capybara.app_host
How `app_host` is set
app_host
will first use ENV["APP_HOST"]
then falls back to the systems
hostname
if the APP_HOST
ENV var is not defined.
If neither are defined, it will then default to "0.0.0.0"
-
-
Capybara.server_host = "0.0.0.0"
Make server listening on all hosts -
-
Capybara.default_max_wait_time = 2
Dont spend forever waiting for matchers -
-
Capybara.default_normalize_ws = true
normalizes whitespace inhas_text?
and similar matchers. -
- Sets the
Capybara.save_path
UsesENV["CAPYBARA_ARTIFACTS"]
and falls back to"./tmp/capybara"
-
- Sets a
REMOTE_CHROME
instance if aENV["CHROME_URL"]
is found -
- Prepends a
last_used_session
attribute accessor to Capybara.
EvilSystems::Helpers
Automatically includes ActionView::RecordIdentifier
if Rails is
defined.
Also includes:
EvilSystems::CupriteHelpers
EvilSystems::SessionHelpers
# The full path to be prepended to a screen shot
absolute_image_path
# The relative path to be prepended to a screenshot message to make it clickable
image_path
# Make failure screenshots compatible with multi-session setup
take_screenshot
# Prepends a '#' to the +dom_id+ method provided by Rails
dom_id(*args)
# Small wrapper around Capybara.using_session thats easy to call from an instance
within_session(name_or_session, &block)
# pauses the page
pause
# Opens a Pry or IRB repl. Will use Pry if Pry is defined, fallsback
# to debugging with IRB
debug binding
# waits to make sure theres no active connections.
wait_for_network_idle!
ENV variables used by this gem.
ENV["APP_HOST"] # used for Capybara.app_host
ENV["CAPYBARA_ARTIFACTS"] # used for Capybara.save_path
ENV["CHROME_URL"] # used for setting a remote chrome instance for Cuprite
ENV["PROCESS_TIMEOUT"] # How long to wait before killing the process, default is 5 seconds
ENV["CI"] # Whether or not to run Cuprite in headless mode, defaults to true.
ENV["SLOWMO"] # Delay in seconds before sending a command (default 0). Also see https://github.com/rubycdp/ferrum#customization
ENV["DISABLE_ANIMATION"] # Configure whether Capybara should render animations, default is true
Thats fine! I totally get it. Selenium is battle tested. Simply remove
the require "capybara/cuprite"
line and EvilSystems
will detect that
Cuprite is not defined and not setup a driver for you and not include
Cuprite helpers.
-
Will use
assets:precompile
instead ofwebpacker:compile
before systems tests (configurable) -
Does not set the
Rails.application.default_url_options[:host]
due to parallelization issues found while testing the dummy app.
The gem is available as open source under the terms of the MIT License.