ant
ant

Reputation: 22948

Testing multistep form with rspec

I'm not very proficient with Capybara and testing tools alike. I'm building a multistep form or a form wizard.

This is how I had a scenario in my head :

This is what I've got so far (I managed to get something working) :

describe "signup" do
  before { visit signup_path }
  let(:submit) { 'Start creating my account' }
  let(:next_btn) { 'Next' }

  describe "with invalid information" do
    it "should not create a user" do
        expect { click_button submit }.not_to change(User, :count)
    end

    describe "should not move to the next step" do
        before { click_button submit }
        it { should have_content('error') }
        it { should have_title('Start here') }
    end
  end

  describe "with valid information wizard step 1" do
    before do
        fill_in 'First name', with: "Example"
        fill_in 'Last name', with: "User"
        fill_in 'email', with: "[email protected]"
        find("#user_password").set "foobar"
    end

    it "should move to the next wizard step 2" do
        click_button submit
        should have_content('We need some more info')
    end
    it "should have error on the wizard step 2" do
        fill_in 'Date of birth', with: "Example"
        click_button next_btn
        should have_content('error')
    end
  end
end

This assertion fails should have error on the wizard step 2, it seems to be stuck at step 1 still, I know this from looking at page content and by errors where Dob element can't be found and next button cant be found as well.

Is this even possible with capybara to test sequentially, keeping information step by step?

Upvotes: 2

Views: 2099

Answers (2)

zetetic
zetetic

Reputation: 47578

You should be able to make this work by nesting the describe blocks when moving on to a subsequent step, eg.

describe "signup" do
...

  describe "with valid information wizard step 1" do
    before do
      fill_in 'First name', with: "Example"
      fill_in 'Last name', with: "User"
      fill_in 'email', with: "[email protected]"
      find("#user_password").set "foobar"
      click_button submit
    end
    it "should move to the next wizard step 2" do
      should have_content('We need some more info')
    end

    describe "and filling out the date of birth incorrectly" do
      before do
        fill_in 'Date of birth', with: "Example"
        click_button next_btn
      end

      it "should have error on the wizard step 2" do
        should have_content('error')
      end
    end
  end
end

Now the button clicks are repeated in the nested blocks, so the first example clicks 'submit', and the second example clicks 'submit' and then clicks 'next_btn', etc. Keep in mind that the sequence is repeated for each example so this may slow down your tests. OTOH it more accurately reflects the user interaction, so the tradeoff is probably worth it.

Upvotes: 4

Kent Rancourt
Kent Rancourt

Reputation: 1595

I think this is not a capybara question so much as it is an rspec question. I've used cucumber more than rspec, but so far as I know in my limited experience, each "describe" is an independent test case. I don't think that you can either a. expect these to execute in any particular order or b. share context / state between tests.

Again, my experience has mainly been with cucumber, but I have written tests for this EXACT scenario before- a two page user registration wizard. In cucumber, one writes "scenarios," which are basically short stories that describe a user's interaction with the the system in terms of "given," "when," and "then" (or in other worse, assumptions, actions, and assertions) and these are written in plain English. One then writes Ruby code that maps these English sentences to Ruby code (which might use capybara) to do / test what each scenario describes... What I did was constructed several distinct scenarios.

  1. User visits registration page; fills it out with a whole bunch of errors; check that the system does display the errors
  2. User visits registration page; fills it out correctly; check that the user makes it to the second page
  3. User has already completed the first page; fills out the second page with a whole bunch of errors; check that the system does display the errors
  4. User has already completed the first page; fills out the second page correctly; check that the user makes it to the confirmation page

You can obviously translate those stories into rspec.

The thing that recurs in those scenarios is the filling out (whether with good or bad data) of the two forms. To keep the code DRY, create some helper methods that let you easily populate the form with values that will help you satisfy each of those scenarios.

Does that help any?

Upvotes: 1

Related Questions