Setting up the Recipe app
To make the guide practical and easy to follow, we will use an app for noting and sharing Recipes. We start from a fresh rails new, add features step by step, and grow complexity as we go. While we add features we will add tests beside the code so you always see how Minitest fits a real codebase.
Assumptions #
-
Ruby is installed.
If you do not have Ruby yet, use rbenv, asdf, mise, or another version manager you like. That makes it easy to switch Ruby per project. You can also start from the official Ruby installation guide.
Once the Ruby is installed, make sure it’s available by checking the version:
ruby -vExample output:
ruby 4.0.2 (2026-03-17 revision d3da9fec82) +PRISM [arm64-darwin25] -
Rails is installed.
To generate a new app, you need Rails already installed globally. Make sure to have that ready. Once the Ruby is setup you can install latest version of Rails with
gem install rails.You can check the version of Rails with:
gem install rails rails -vExample output:
Rails 8.1.3
What you will do in this chapter #
- You will generate the Recipes app
- Install gems
- Prepare the test database
- Run the default Minitest suite so you trust your machine before we talk theory in the next chapter
By the end you should get green output from bin/rails test:all at the root of your recipes app.
Generate the Recipes app #
Onto the exciting part, we will generate a new Rails app for Recipes that we will be using for adding features and tests.
- Open a terminal.
-
cdto the folder where you keep projects (change the path to match your machine):cd ~/projects -
Confirm where you are:
pwdYou should see the path you expect. The next command will create a sibling folder next to whatever else lives here.
-
Generate the app
rails new recipesrails newcreates a directory namedrecipesand fills it with a full Rails skeleton.
What each part of the command means #
| Part | Meaning |
|---|---|
rails new |
Rails generator. Creates a new application skeleton. |
recipes |
Directory name and default module name. That is the Recipes app for the rest of the guide. |
What you should see #
When the generator finishes, list the new folder:
ls recipes
You should see app/, config/, db/, test/, Gemfile, config.ru, and other usual Rails files.
This means Rails app is now setup.
System test gems in the Gemfile #
Open Gemfile and find the group :test do block. It should include:
group :test do
# Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
gem "capybara"
gem "selenium-webdriver"
end
Ensure these two gems are inside the Gemfile, they are required for system tests to work properly.
NOTE: If those lines are missing, add them under group :test, save, then run bundle install again.
First git commit #
This step is optional but recommended. Make a first commit so you can roll back if a later step goes wrong:
cd recipes
git status
git add .
git commit -m "Initialize Recipes app"
What is inside test/ #
Let’s take a look at files and folders inside the test folder. To do that, hit the following command from the app root:
ls test
You should always see at least:
| Path | Role |
|---|---|
test/test_helper.rb |
Boots test, loads rails/test_help, shared Minitest setup (for example fixtures and parallel workers). |
test/controllers/ |
Controller tests when you use them. |
test/models/ |
Model tests: validations, scopes, plain Ruby on your models. |
test/integration/ |
Integration tests: full HTTP cycle through routing, controller, and often views. |
test/fixtures/ |
YAML fixtures for sample rows. |
test/mailers/ |
Mailer tests. |
test/helpers/ |
Helper tests (we use them rarely). |
Why test/system might be empty at first #
On a plain Rails 8 app, the test/system directory and test/application_system_test_case.rb file are often not created until you generate your first system test. Maintainers summarized the default like this:
System tests are a nice to have but don’t make sense to be generated by default since you don’t want to test every endpoint this way. They should be used for testing critical paths, especially where JS is involved.
We will still use system tests where they earn their keep: critical flows and smoke checks that the app boots in a real browser.
Don’t worry about missing folder and file yet, we will get both of them when we generate one system test in the app later in this chapter, we will talk more about these files and folder there. For more detail about the removal decision of system tests from defaults, you can check following pull requests in the Rails repository:
Prepare the test database #
Rails uses a separate database for RAILS_ENV=test. Prepare it once so you do not chase connection errors during your first run:
RAILS_ENV=test bin/rails db:prepare
What that does:
- Loads the app in test
- Creates the test database if it is missing
- Applies the schema so it matches
db/schema.rb
Run non-system tests #
bin/rails test
That runs everything under test/ except files inside test/system. Use it when you want a fast loop without booting the browser.
How to read the output #
Example shape:
Run options: --seed 12345
# Running:
..
Finished in 0.012345s, 161.8 runs/s, 161.8 assertions/s.
2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
- runs — how many
test "..." doblocks ran - assertions — how many
assert_*calls ran - failures — failed assertions
- errors — unexpected exceptions
- skips — tests you marked skipped with
skip "this test"inside the test block
A brand new app ships a small number of sample tests. The exact counts are not important. You want 0 failures and 0 errors.
Add system tests (generator + smoke test) #
Right now we don’t have any system test setup because Rails 8 doesn’t ship that by default as already noted in previous sections. So, let’s now setup the system test and add one simple system test to ensure it’s working.
Generate a system test scaffold:
bin/rails generate system_test rails_default_pages
That should create (names matter):
| File | Role |
|---|---|
test/application_system_test_case.rb |
Base class for every system test: Capybara + Selenium driver. |
test/system/rails_default_pages_test.rb |
First system test file (we replace its body in a moment). |
What is inside test/application_system_test_case.rb #
require "test_helper"
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ]
end
require "test_helper"— same boot path as other tests (ENV,config/environment, Minitest helpers).ApplicationSystemTestCase— inheritsActionDispatch::SystemTestCase, Rails wrapper around Capybara + a driver.driven_by :selenium, using: :headless_chrome, ...— runs Chrome without opening a window. Good for day to day runs.
NOTE: You need a working Chrome or Chromium install for system tests to work. If bin/rails test:system fails with a driver error, install Chrome and retry.
Smoke test for /up #
A new Rails app already exposes the health check at /up (see config/routes.rb). That gives a boring, stable URL for your first visit.
Replace test/system/rails_default_pages_test.rb with:
require "application_system_test_case"
class RailsDefaultPagesTest < ApplicationSystemTestCase
test "health check responds over the browser" do
visit "/up"
assert_current_path "/up"
end
end
Line by line:
test "..." do— names the example in Minitest output.visit "/up"— Capybara drives the browser to that path on the test server (not necessarily port 3000; Rails picks a free port).assert_current_path "/up"— Checks if the URL in the browser equals/upor not. Fails the test if the URL doesn’t match.
Run system tests only:
bin/rails test:system
You want 0 failures and 0 errors. Assertion count can differ slightly by Rails version; the important part is green.
Run everything together #
You can also run all tests (unit, integration, and system) in one go. On a fresh app it is a quick confidence check before you start building features. You can run them all with the following command:
bin/rails test:all
That runs non-system tests and test/system in one go. After this chapter you should see at least the default tests plus your /up system test in the combined output.
End of chapter 1 #
You now have:
- A Recipes app with Minitest under
test/ - Capybara and Selenium ready for system tests
- A green starting point for the Recipes app that you will begin building in chapter 5
- A green
bin/rails test:allon your machine
You have not built recipe screens, validations, or mailers yet. That is intentional. We will start adding features only when we reach Chapter 5. Before that we will go over a bit of theory regarding automated tests.
When you are ready, continue to Kinds of Rails tests (and when to use each).
Disclaimer
This guide is written in tandem with AI but reviewed and enhanced by me based on my experience with Rails and testing. I stand by the advice and patterns here.