find 方法不等待 json 文件中出现的元素

find method is not waiting for elements that will appear from a json file

目前,我有这个测试:

spec/features/cardx/cardx_spec.rb

it 'can edit cardx with the form' do
  product = FactoryGirl.create(:product)
  store = FactoryGirl.create(:store)
  click_link(class: 'link-record-edit')
  page.find(class: 'record-form')
  fill_in 'field-start-date', with: Date.tomorrow.to_s
  page.find(id: 'cardx-edit-form').fill_in 'field-end-date', with: (Date.tomorrow + 7).to_s
  page.find(id: 'cardx-edit-form').select(product.name, from: { id: 'field-product' })
  page.find(id: 'cardx-edit-form').select(store.name, from: { id: 'field-store' })
  page.find(id: 'cardx-edit-form').click_button(t('button.save'))
  changed = Cardx.find(@cardx.id)
  result = changed.start_date == Date.tomorrow && changed.end_date == (Date.tomorrow + 7) && changed.product.name == product.name && changed.store.name == store.name
  expect(result).to eq(true)
end

此测试应该检查我是否可以提交表单,但是此表单正在呈现并通过 AJAX 请求添加到 DOM,当我单击 link 在页面中。此渲染来自 JSON 文件。 当我作为用户正常使用浏览器时,一切正常,但是当我 运行 这个测试时(即使我将 max_timeout 设置为像 50 秒这样荒谬的值),它立即失败说它不能找到 'record-form' 元素。 find 不是应该等到 max_timeout 运行 出来吗?

在我的测试中显然发生的是它没有尝试加载和呈现带有表单代码的 JSON 文件。这个问题有解决办法吗?

编辑:我目前拥有的代码

javascript 加载表单

$(document).on('click', '.link-record-edit', function(e) {
    //diferentiate between multiple searches on page
    setRecord(this);

    //set selected id
    record[record_type].selected_id = $(this).attr('data-id');

    //mark selected row
    markSelectedRow();

    if(record_type !== "default") {
       //if in tab, open modal
      $(record[record_type].form_placeholder).modal();
    }

    //get ID for edition
    (loadForm || console.error)(e);

    e.preventDefault();
  });

function loadForm(ev, callback) {
  //validate
  if (typeof record[record_type].path_edit === 'undefined') {
    return console.error("No definition for 'record[record_type].path_edit' on your page's js");
  }

  target = [];
  _event = null;
  if(typeof event === 'undefined' || event === null) {
    _event = ev;
  } else {
    _event = event;
  }
  if(_event.srcElement !== undefined && _event.srcElement.className !== undefined) {
    target = _event.srcElement.className.split(" ");
  } else if(_event.target !== undefined && _event.target.className !== undefined) {
    target = _event.target.className.split(" ");
  }

  //show form block
  $form_placeholder = "";
  if(record_type === "default") {

    //is nome cases, with tabs, preselect first tab
    $('[role="tabpanel"] a:first').tab('show');

    //if selected in default list, empty tab placeholders
    $('.tab-pane [data-placeholder="true"]').html('');

    //add sidebar form
    $('.width-switcher').filter(':visible').removeClass('col-sm-12').addClass('col-sm-6');
    $('.width-switcher:hidden').fadeIn('fast');
    $form_placeholder = record[record_type].form_placeholder;

  } else if(target.indexOf("link-record-edit") > -1 || target.indexOf("link-record-new") > -1) {
    $form_placeholder = record[record_type].form_placeholder + ' .modal-content';
  }

  //last case cenario
  if(record[record_type].inline_placeholder != null && $($form_placeholder).length == 0) {
    $form_placeholder = record[record_type].form_placeholder;
  }

  loadSpinner($form_placeholder);


  //enable/disable tabs
  if(record[record_type].selected_id > 0 && record_type === "default") {
      $(".nav-tabs").show();
  } else if(record_type === "default") {
      $(".nav-tabs").hide();
  }

  // Remove temporary buttons from hooks
  $('.temporary').remove();

  // pass var to form of view/edit mode
  $edit_mode = $('.editor-mode.active').length;

  //get form data and place it on placeholder
  $.ajax({
    url: record[record_type].path_edit.replace(':id', record[record_type].selected_id),
    type: "GET",
    dataType: "html",
    data: { parent_id: record[record_type].parent_id, edit_mode: $edit_mode },
    success: function(result) {
      //add form
      $($form_placeholder).fadeOut(100, function() {
        $(this).html(result).fadeIn(400, function() {
          //as it fades in, set title and prettify form objects

          //change title
          setFormTitle();

          //refresh scripts for forms
          formPluginRegresh();

          //new html on page, redistribute record types attributes
          distributeRecordAttributes();

          removeSpinner();

          //callback if anyone waits
          if(callback != null) { callback(); }
        });
      });
    },
    error: function(jqXHR, textStatus, errorThrown) {
      showMessage('error', $.parseJSON(jqXHR.responseText));
    }
  });
}

function update_inline_combos() {
  //case inline, update dropdownlist
  if($(record[record_type].form_placeholder).parents('.overflow').length > 0) {
    //check existance of drops
    drops = $('.input-group[data-record="'+record_type+'"]').find('> select');

    //fill in new data
    $.ajax({
        url: record[record_type].path_list_drop,
        type: "GET",
        dataType: "html",
        success: function(result) {
          $.each(drops, function(index, value) {
            //element's id
            $id = $(value).attr('id');

            //add new data with :id, :name
            setBoot('#'+$id, result);
          });
        },
        error: function(jqXHR, textStatus, errorThrown) {
          showMessage('error', $.parseJSON(jqXHR.responseText));
        }
    });
  }
}

HTML 我有

index.html

<div class="col-sm-6 col-xs-12 width-switcher not-visible">
        <div class="box-container">
            <div class="box-header">
                <span class="title" id="edit-cardx-title">&nbsp;</span>

                <!-- Split button -->
                <button class="btn btn-xs btn-default pull-right close-width-switcher" type="button">
                    <i class="fa fa-close"></i>
                </button>
            </div>

            <div class="box-content no-padding">
                <div id="placeholder-form-cardx">
                    <!-- FORM PLACEHOLDER -->
                </div>
            </div>
        </div>
    </div>

_form.etml(将放在占位符上的部分)

<%= render partial: 'partials/form_objects/form_title', format: :erb, locals: { optional: true } %>

<%= simple_form_for(@cardx, remote: true,
    url: url_for(action: 'update_or_create', controller: 'cardxes', format: 'json'),
    html: { method: 'post', id: 'cardx-edit-form' },
    authenticity_token: true)  do |f| %>

    <%= f.error_notification %>
    <%= f.hidden_field :id %>

    <div class="form-inputs form-group">
        <div class="col-lg-2 col-md-3 col-sm-4 control-label">
            <%=t("label.start_date")%>
        </div>
        <div class="col-lg-10 col-md-9 col-sm-8">
            <%= f.input :start_date, as: :string,
            input_html: {class: "date-picker day-datepicker", id: "field-start-date"},
            label: false, required: true, class: "form-control" %>
        </div>
    </div>

    <div class="form-inputs form-group">
        <div class="col-lg-2 col-md-3 col-sm-4 control-label">
            <%=t("label.end_date")%>
        </div>
        <div class="col-lg-10 col-md-9 col-sm-8">
            <%= f.input :end_date, as: :string,
            input_html: {class: "date-picker day-datepicker", id: "field-end-date"},
            label: false, required: true, class: "form-control" %>
        </div>
    </div>
    <!--
    <div class="form-inputs form-group">
        <div class="col-lg-2 col-md-3 col-sm-4 control-label">
            <%#=t("label.end_date")%>
        </div>
        <div class="col-lg-10 col-md-9 col-sm-8">
          <%= f.collection_select :store_id,
              Store.to_collection.list, :id, :name,
              { include_blank: t("form.choose") },
              { class: "required" } %>
        </div>
    </div>
    -->
    <div class="form-inputs form-group">
        <div class="col-lg-2 col-md-3 col-sm-4 control-label">
            <%=t("label.store.one")%>
        </div>
        <div class="col-lg-10 col-md-9 col-sm-8">
          <%= f.collection_select :store_id,
              Store.to_collection.list, :id, :name,
              { include_blank: t("form.choose") },
              { class: "required selectpicker", id: "field-store" } %>
        </div>
    </div>

    <div class="form-inputs form-group">
        <div class="col-lg-2 col-md-3 col-sm-4 control-label">
            <%=t("label.product.one")%>
        </div>
        <div class="col-lg-10 col-md-9 col-sm-8">
          <%= f.collection_select :product_id,
              Product.to_collection.list, :id, :name,
              { include_blank: t("form.choose"), required_field: true },
              { class: "selectpicker required", id: "field-product" } %>
        </div>
    </div>

    <script>
    $(function() {
      $('.selectpicker').selectpicker({
    
        liveSearch: true,
        liveSearchNormalize: true,
    
        size: 6,
    
        width: '100%',
        dropupAuto: true,
        actionsBox: false
    
      });
    });
    </script>

    <%= render partial: "partials/form_objects/form_actions",
               format: :erb,
               locals: { f: f, record: @cardx } %>

<% end %>

提前致谢

编辑:

我正在使用这个测试(为简单起见)来检测表单是否已加载并且我得到'无法找到css“#cardx-edit-form”'

it 'show edit form when a cardex record is clicked' do
      page.find('.link-record-edit', match: :first).click
      page.find('#cardx-edit-form', wait: 50)
      expect(page).to have_selector('#cardx-edit-form')
    end

您的测试没有用 js: true 元数据标记,并且没有发生等待行为这一事实表明您正在使用 rack_test 驱动程序进行此测试。 rack_test 驱动程序不支持 JS,因此也不进行任何等待(因为没有 JS 支持,就没有要等待的异步操作)。您应该能够从错误的堆栈跟踪中确认这一点,该错误可能会引用名称中带有 'capybara/rack_test' 的文件。参见 - https://github.com/teamcapybara/capybara#drivers and https://github.com/teamcapybara/capybara#using-capybara-with-rspec