2
votes

I have an input form for a Sales_Opportunity, and I use Javascript to add an option to the bottom of a select dropdown to "Add new company" (Sales_Opportunity belongs_to a Company, and a User can either select an existing company or add a new one using this option). If the User clicks "Add new company" then the page opens a Bootstrap3 Modal box form for the Company, and upon submission (if successful) the page adds a new option with the newly created Company name on it and automatically selects this option. The code above works perfectly, and now I'm trying to write an Rspec/Capybara test to ensure it doesn't break in the future (I know - I should be writing the tests first, but as a newbie I find it easier to test in the browser and then write a test I can re-use on other Jquery/Modal objects later).

In any case - here is the test that is failing (from my Users page):

    it 'can add a new company via the sales opportunity form'do
  page.click_link('Add sales opportunity')
  expect(page).to have_content('Add new company')
  page.select('Add new company', :from => "Company")
  page.fill_in('Company name', with: "Modal Company")
  page.find("#modal-form").click_button("Save")
  expect(page).to have_content("Modal Company")
end

The User clicks "Add sales opportunity" and is taken to the form for that Sales Opportunity. The Rspec test fails on the line "page.select('Add new company', :from "Company") - so it appears that the line prior is working correctly, and Capybara is waiting for the content to appear on the page. However the next line (page.select) is clearly not waiting for the content to be loaded.

I have tests above that perform the same action - but they select an existing company from the database and pass it through to generate a Sales_Opportunity, so I know that part of my code works just fine, and they are selecting the company from the same drop-down, so Capybara can find other elements within that Select field.

In case my Jquery is of use:

$(function() {

//select the companies select dropdown and add in a "add new" item
  (function () {
    $('#sales_opportunity_company_id').append($('<option></option>', {
          text: 'Add new company',
        }))
    })();

//select the "add company" field and open a modal to insert a new company into the DB with Ajax
$('#sales_opportunity_company_id').on('change', function() {
  if ($(this).val() == 'Add new company') {
    // Hide the submit button if "Add new company is selected"
    $('.well .btn').hide();
    var newvalue = false;
    //call a modal for adding a new company
    $('#competitor_modal').modal('show');
    //select the input field automatically
    $('.modal').on('shown.bs.modal', function() {
    $("#company_company_name").focus();
    });
    //get the organization_id
    var Org;
    Org = $('#organization_id').attr('data-organizationid');
   //pass the organization_id to the hidden text box
    $('#company_organization_id').val(Org);

  }
    else {
        $('.well .btn').show();
        $input = $('#company_error');
        $input.closest('.form-group').removeClass('has-error').find('.warning-block').html('');
    }
});

 //add a warning to the company selector if the "add new company" field is checked and no company was added
 $('.modal').on('hide.bs.modal', function() {
   if ($('#sales_opportunity_company_id').val() == 'Add new company') {
   $input = $('#company_error');
   $input.closest('.form-group').addClass('has-error').find('.warning-block').addClass('col-md-8-offset-4').html('Select a Company from the list above, or add a new company to enable saving');
   $input.closest('.form-group .select').addClass('has-error');
   $("#sales_opportunity_company_id")[0].selectedIndex = -1;
  }

  else {
    $(this).clear_previous_errors();
  }
 });
});

How do I get Capybara to select this newly added item? I note that wait_until was deprecated in v2 of Capybara, so it seems that's no longer an option (I'm using 2.3.0).

EDIT: here is the result of the failing test for completeness;

  1) User pages sales opportunities can add a new company via the sales opportunity form
 Failure/Error: page.select('Add new company', :from => "Company")
 Capybara::ElementNotFound:
   Unable to find option "Add new company"
 # ./spec/requests/user_pages_spec.rb:186:in `block (3 levels) in <top (required)>'

Any ideas?

EDIT 2:

OK, so I've now tried a range of items, and I'm getting some strange results.

Using the following Capybara test:

 it 'can add a new company via the sales opportunity form'do
  page.click_link('Add sales opportunity')
  expect(page).to have_content('Add new company')
  sleep(2)
  print page.html
  #page.select('Add new company', :from => "Company")
  page.fill_in('Company name', with: "Modal Company")
  page.find("#competitor_modal").click_button("Save")
  expect(page).to have_content("Modal Company")
end

I get no error thrown by the line "expect(page).to have_content('Add new company')". But as you can see from the html printed below, I also don't actually have that element showing up on my page. Any idea why Javascript isn't working here?

       <div class="form-group" id= "company_error">
        <label class="col-md-4 control-label" for="sales_opportunity_company_id">Company</label>
        <div class ="col-md-8", id="company_select">
         <select id="sales_opportunity_company_id" name="sales_opportunity[company_id]"><option value="23398">Test Company</option></select>
         </div>
           <span class="warning-block"></span>
        </div>
2

2 Answers

2
votes

I finally managed to fix this - I needed to use the Poltergeist gem in order to run the javascript in a headless browser, and also to use code pasted at the bottom to ensure the databases used for testing could see each other's data (otherwise the authentication methods wouldn't work).

Final working capybara/Rspec/Poltergeist test:

it 'can add a new company via the sales opportunity form', js: true do
  page.click_link('Add sales opportunity')
  page.select('Add new company', :from => "Company")
  page.fill_in('Company name', with: "Modal Company")
  page.find("#competitor_modal").click_button("Save")
  page.has_select?('Company', :selected => 'Modal Company')
end

Code to ensure the User specs still work (in spec/support/shared_db_connection.rb):

class ActiveRecord::Base
 mattr_accessor :shared_connection
 @@shared_connection = nil

def self.connection
 @@shared_connection || retrieve_connection
end
end

# Forces all threads to share the same connection. This works on
# Capybara because it starts the web server in a thread.
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection

I used the Railscast #391 in order to get most of this working, but also ran a lot of debugging using the extremely useful Capybara method:

print page.html

Which showed when the Javascript was actually working and allowed me to use the right methods to find it on the page.

Thanks for your help too @Mohamed Yakout!

1
votes

I think you need to use this step:

Given(/^I wait for (\d+) seconds?$/) do |n|
 sleep(n.to_i)
end

Then use this code And I wait for 2 seconds after this page.click_link('Add sales opportunity') to allow load options for #sales_opportunity_company_id select.