I have a single page Sinatra app that has a multistep form/wizard interface. If I want to test the form with Capybara, will need to repeat all the steps for each test? I'm hoping to avoid something like this:
it "visits the home page" do
vist "/"
page.should have_content('foo')
end
it "clicks the first button" do
vist "/"
page.should have_content('foo')
button_click("Next")
end
it "clicks the second button" do
vist "/"
page.should have_content('foo')
button_click("Next")
page.should_have_content('bar')
end
it "clicks the third button" do
vist "/"
page.should have_content('foo')
button_click("Next")
page.should_have_content('bar')
button_click("Next")
end
I found an article about nested tests using RSpec and Capybara, but haven't been able to get a similar technique to work with Minitest.
I've done some research for you, and I'll share with you what I've found.
In order for doing this, you should consider "converting" your Minitest
tests, to specs. This gives you access for similar syntax, as RSpec
's - describe
with capability of nesting them.
I'll simplify the code to provide example, but it should be clear where to put your logic.
Let's check couple examples.
1). Let's do some simple test for Array
:
require "minitest/autorun"
describe Array do
before do
@arr = []
end
describe "when initialized" do
it "is empty" do
@arr.length.must_equal 0
end
end
end
This should pass, nothing really fancy here.
2). Let's add another describe
, nested to one we have:
describe Array do
before do
@arr = []
end
describe "when initialized" do
it "is empty" do
@arr.length.must_equal 0
end
describe "when element added" do
it "length reflects the change" do
@arr << "a"
@arr.length.must_equal 1
end
end
end
end
This also works - an element has been added to the array, and its length
indicates that properly.
3). Let's try nesting another block. We're hoping, that @arr << "a"
will be preserved, so if we add another element, @arr.length
will be 2. Let's see:
describe Array do
before do
@arr = []
end
describe "when initialized" do
it "is empty" do
@arr.length.must_equal 0
end
describe "when element added" do
it "length reflects the change" do
@arr << "a"
@arr.length.must_equal 1
end
describe "when another element added" do
it "length also reflects the change" do
@arr << "b"
p @arr
@arr.length.must_equal 2
end
end
end
end
end
describe
is nested within another describe
- as we would do for RSpec, but unfortunately, it seems that the result of @arr << "a"
is not preserved, and the nested describe
's @arr.length
is also 1.
I have left p @arr
in the code, so you can easily see in your console what is currently stored in @arr
.
Definitely not what we expected... Let's try something crazy then...
4). Let's nest describe
within... it
:
describe Array do
before do
@arr = []
end
describe "when initialized" do
it "is empty" do
@arr.length.must_equal 0
end
describe "when element added" do
it "length reflects the change" do
@arr << "a"
@arr.length.must_equal 1
describe "when another element added" do
it "length also reflects the change" do
@arr << "b"
p @arr
@arr.length.must_equal 2
end
end
end
end
end
end
Well, it turns out, that this is completely valid and it behaves exactly as we expected! (Again, p @arr
left here so you an check in console what is currently stored in @arr
).
To be honest - I didn't check that with Capybara
, but this simple example is quite promising. Try modifying your code accordingly, so in your specs the Capybara
interactions are implemented.
Let me be clear about provided solution: I strongly advise agains this approach:
- Specs like this are difficult to read - and in result - difficult to maintain.
- This is considered bad pattern. Next steps should not rely on result of previous steps.
If you want to test your contoller properly, you should try something similar to this (this is pseudo code just to illustrate idea):
Test for step 1
post "/url-to-my-form", { params_step_1: { ... } }
Test for step 2
post "/url-to-my-form", { params_step_1: { ... }, params_step_2: { ... } }
With this approach is very easy to see what params
are post
ed, thus it's easier to test against eg. violations of any rules (empty values, invalid email, etc...).
Hope that helps! Good Luck!