简体   繁体   中英

Rspec capybara - checking a checkbox suppose to be triggering AJAX request but not working

I have form that has an delivery_address input field and checkbox that will trigger an AJAX call to retrieve the default address and populate the delivery_address field.

This feature is working fine on the browser! But when I am trying to write a test for it on rspec , it doesn't seems to work

HTML snippet:

<div class="form-group col-lg-12">
   <label for="order_delivery_address">Delivery address</label>
   <input type="text" name="order[delivery_address]" id="order_delivery_address" class="form-control" required="required" placeholder="Enter a location" autocomplete="off">
   <label class="default-address-label">
     <input type="checkbox" name="default_address" id="default_address" value="1">
       Use my default address
    </label>
</div>

JS snippet:

var $order_details_form = $('.order-details-form');
var $delivery_address_input = $order_details_form.find('#order_delivery_address');

$order_details_form.find('#default_address').change(function() {
  if($(this).is(':checked')){ //checkbox is tick
    $.ajax({
        type: 'GET',
        url: '/order-details/get-user-default-address',
        data: {
           'userId': $order_details_form.find('#order_user_id').val()
        },
        dataType: 'json', 
        success: function(data) {        
          //populate the delivery address input field with default address        
          var default_address = data.default_address;
          $delivery_address_input.val(default_address);
       },
       error: function (textStatus, errorThrown) {
          //display error message and uncheck the default address checkbox
          toastr.error('Error retrieving your default address at the moment. Please try again.');
          $order_details_form.find('#default_address').prop('checked', false);
        }
    });
  }
});

Controller snippet:

def get_user_default_address
    default_address = User.find(params[:userId]).address.full_address
    respond_to do |format|
      format.json { render :json => { :default_address => default_address } }
    end
end

Rspec snippet:

context 'default address' do
  let!(:user){ create :user }
  let!(:address1){ create :address, user: user}

  it 'should proceed with default address selected', js: true do
    expect(page.current_path).to eq(order_details_path)    
    expect(find('#order_user_id', visible: false).value).to eq(user.id.to_s)
    expect(page.find('#default_address')).to_not be_checked
    check 'default_address'
    expect(page.find('#default_address')).to be_checked
    expect(page.find('#order_delivery_address').value).to eq address1.full_address
  end
end

The test result fails at this line expect(page.find('#order_delivery_address').value).to eq address1.full_address , where I got empty string instead of the address which indicates that the delivery_address field wasn't populated.

I think it doesn't seems to be even making the AJAX request because I've tried inserting binding.pry into the controller get_user_default_address and the binding.pry is not even triggered.

Any idea what am I missing out here? Any help would be appreciated!

*Note: i am using capybara webkit and it has been configured properly as my other test cases that uses js works successfully.

This is usually caused by one of three things.

  1. Not actually using a JS capable driver for the test. You claim it is running with capybara-webkit, which is a JS capable driver, and that other tests work fine with JS so this is probably not the issue.

  2. Error in JS. By default, in dev mode each JS asset is loaded separately but in test and production modes they are all concatenated into one file to reduce the number of requests. This means that an error in any one of your JS assets that is concatenated before the JS snippet which handles your delivery address checkbox can cause the handler to never get attached. That combined with the fact that capybara-webkit only really supports up to ES5 (without polyfill/transpiling) means you can end up with "errors" in your JS that aren't actually errors in the real browser you're testing with (use of let, const, ES5.1+ methods, etc). You can see if this is the issue by enabling debug mode in capybara-webkit to see if that shows errors and/or running with selenium and a real browser to see if the issue goes away.

  3. Use of the wrong RSpec matchers. The RSpec provided eq matcher doesn't provide any sort of waiting/retrying behavior. When combined with the fact there is no guarantee all side effects triggered by an action initiated in the browser have completed when Capybaras check / click /etc return means you will potentially have all sorts of flaky tests/failures. Instead you should be using the Capybara provided RSpec matchers which provide waiting/retrying behavior. As a general rule you shouldn't be using the eq matcher for anything to do with elements on your page. In your case that would mean your test becoming

     it 'should proceed with default address selected', js: true do expect(page).to have_current_path(order_details_path) # NEVER use `eq` matcher with current_path expect(find('#order_user_id', visible: false).value).to eq(user.id.to_s) expect(page).to have_unchecked_field('default_address') # same as have_field('default_address', checked: false) check 'default_address' expect(page).to have_checked_field('default_address') expect(page).to have_field('order_delivery_address', with: address1.full_address) end 

    The one use of eq that remains in that test is because the Capybara :field selector doesn't find inputs of type 'hidden' (which I assume #order_user_id is) and once you're on the order_details_path the input should already exist. Therefore this is one of the few cases where using the eq matcher would be acceptable, if you REALLY need to verify this input. Generally you shouldn't be worried about verifying anything the user can't see in a feature test since it's an implementation detail, and if the value was missing/wrong it would show in a test that verifies the functionality of submitting the form.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM