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"> </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
目前,我有这个测试:
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"> </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