Rspec capybara - 检查一个复选框,假设是触发AJAX请求但没有工作

时间:2018-01-06 05:50:58

标签: ruby-on-rails rspec capybara

我的表单包含delivery_address输入字段和复选框,可触发AJAX调用以检索默认地址并填充delivery_address字段。

此功能在浏览器上正常运行!但是当我试图在rspec上为它编写测试时,它似乎无法正常工作

HTML片段:

<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片段:

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片段:

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

测试结果在此行expect(page.find('#order_delivery_address').value).to eq address1.full_address处失败,其中我得到空字符串而不是指示未填充delivery_address字段的地址。

我认为它似乎没有提出AJAX请求,因为我尝试将binding.pry插入控制器get_user_default_address,而binding.pry甚至没有触发。

知道我在这里错过了什么吗?任何帮助将不胜感激!

*注意:我正在使用capybara webkit并且已经正确配置,因为我使用js的其他测试用例成功运行。

1 个答案:

答案 0 :(得分:0)

这通常是由三件事之一引起的。

  1. 实际上没有使用支持JS的驱动程序进行测试。你声称它运行的是capybara-webkit,它是一个支持JS的驱动程序,而其他测试可以正常使用JS,所以这可能不是问题。

  2. JS中的错误。默认情况下,在开发模式下,每个JS资产都单独加载,但在测试和生产模式下,它们都连接成一个文件以减少请求数。这意味着在处理您的传递地址的JS片段之前连接的任何一个JS资产中的错误都会导致处理程序永远不会被附加。这与capybara-webkit仅支持ES5(没有polyfill / transpiling)的事实相结合意味着你最终可以得到错误&#34;在您的JS中,您在使用let,const,ES5.1 +方法等进行测试的真实浏览器中实际上并不存在错误。您可以通过在capybara-webkit中启用调试模式来查看是否存在此问题,以查看是否显示错误和/或使用selenium和真实浏览器运行以查看问题是否消失。

  3. 使用错误的RSpec匹配器。 RSpec提供的check匹配器不提供任何类型的等待/重试行为。当与事实相结合时,无法保证当Capybaras click / eq / etc返回意味着您可能会进行各种片状测试/失败时,浏览器中启动的操作所触发的所有副作用都已完成。相反,您应该使用Capybara提供的RSpec匹配器来提供等待/重试行为。作为一般规则,您不应该使用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 匹配器来处理页面上的元素。在您的情况下,这将意味着您的测试成为

    eq

    保留在该测试中的eq的一次使用是因为Capybara:字段选择器找不到类型&#39;隐藏&#39;的输入。 (我假设#order_user_id是),一旦你在order_details_path上,输入应该已经存在。因此,如果您真的需要验证此输入,这是少数几种使用var http = require("http"); var fs = require('fs'); //var bodyParser = require("body-parser"); //var moment = require("moment"); var options = { "method" : "GET", "hostname" : "xxx.xxx.xxx.xxx", "port" : "18080", "path" : "/api/v1/applications/" }; exports.getId = function(callback) { var req = http.request(options, function (res) { var chunks = []; res.on("data", function (chunk) { chunks.push(chunk); }); res.on("end", function () { var body = JSON.parse(Buffer.concat(chunks)); var arrFound = Object.keys(body).filter(function(key) { if (body[key].name.indexOf("TestName") > -1) { return body[key].name; } }).reduce(function(obj, key){ obj = body[key].id; return obj; }, {});; //console.log("Name: ", arrFound); callback(null, arrFound)); }); }); req.end(); } 匹配器的情况之一。通常,您不应该担心验证用户在功能测试中看不到的任何内容,因为它是一个实现细节,如果值丢失/错误,它将在验证中显示提交表格的功能。