At last Thursday’s Code With Jason Meetup I was in the hot seat with CRMmy, my CRM side project. We spent most of our time talking through some feature tests, taking them from a single initial stream of consciousness test to a higher quality set of tests.
When I start building out a new feature, I typically start with walking through the navigation and screen I wish were there using feature tests. This ends up being very low level which is hard to work with long term, but it means the requirements are explicit. The feature I was looking at was left at this stage and look like this initially:
RSpec.feature "UsersCanManageProjects", type: :feature do
scenario "successfully", :js do
user = create(:user, :with_account)
visit root_path(as: user)
click_on "Select"
click_on "Projects", match: :first
click_on "Add Project"
fill_in "Name", with: "My Project"
click_on "Create Project"
click_on "My Project"
click_on "Edit"
fill_in "Name", with: "New Project"
click_on "Update Project"
expect(page).to have_content "New Project"
end
end
Some explanation was required for some parts of the test, for example the click_on "Select"
is needed to select the active account and the match: :first
is needed to pick a menu since there is a desktop and mobile menu. As usual, when you code needs to be explained, you need better code! We addressed that later on.
The first change I wanted to make was with the scenario name itself "successfully"
is obviously bad and reflects that I hadn’t thought through exactly what I was going to be testing.
Rather than working through that through, Jason suggested breaking it out into a few separate tests. I’m not one to reach for AI in a scenario like this, but at Jason’s recommendation I did, and with a simple prompt of break up the following test into multiple scenarios
, it gave me something pretty close to this:
RSpec.feature "UsersCanManageProjects", type: :feature do
let(:user) { create(:user, :with_account) }
before do
visit root_path(as: user)
click_on "Select"
end
scenario "navigate to projects page" do
click_on "Projects", match: :first
expect(page).to have_content "Projects"
end
scenario "add a project" do
visit projects_path
click_on "Add Project"
fill_in "Name", with: "My Project"
click_on "Create Project"
expect(page).to have_content "My Project"
end
scenario "edit a project" do
project = create :project, account: user.accounts.first
visit projects_path
click_on project.name
click_on "Edit"
fill_in "Name", with: "New Project"
click_on "Update Project"
expect(page).to have_content "New Project"
end
end
The test is quite a bit longer, but much more specific. Each scenario should likely fail for more explicit reasons since they are significantly more isolated, they are more clear and understandable, and critically, I can see where I should be putting additional tests for the next thing I add.
We still hadn’t addressed some of the icky “explain your code” issues. This ended up being a pretty simple set of changes:
def click_nav(label)
within "#desktop-nav" do
click_on label
end
end
scenario "navigate to projects page" do
click_nav "Projects"
expect(page).to have_content "Projects"
end
Overall, this test went from being very low level, way to large, with several “gotchas”, into a much understandable test that provides a better foundation to continue building on, and giving a few improvements that were used to improve other tests.