Capybara 和 JavaScript:检查可见性需要大量时间!如何优化

Capybara and JavaScript: checking for visibility requires huge amounts of time! How to optimise?

本文关键字:时间 何优化 优化 JavaScript 检查 可见性 Capybara      更新时间:2023-09-26

在Rails中创建一些JavaScript功能时,我使用了一些丑陋的Capybara规范来帮助我确保一切正常。其中一个规范如下所示:

it 'creates a report document', js: true do
  visit new_project_report_document_path @project
  expect(page).to have_active_navigation_items 'Projects'
  expect(page).to have_breadcrumbs 'A4AA 2.0', 'Projects', 'Project test name', 'Reports', 'Create'
  expect(page).to have_headline 'Create Report'
  expect {
    select 'Template 1', from: 'report_report_template_id'
  }.to change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}']", visible: true }.from(false)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}'] #report_name[disabled]",        visible: false}.from(true)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}'] #report_description[disabled]", visible: false}.from(true)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}'] #report_intro[disabled]",       visible: false}.from(true)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}'] #report_content[disabled]",     visible: false}.from(true)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}'] #report_outro[disabled]",       visible: false}.from(true)
  expect(page).to have_css "[data-template-inputs-id='#{@report_template_1.id}'] #report_name",        text: @report_template_1.name
  expect(page).to have_css "[data-template-inputs-id='#{@report_template_1.id}'] #report_description", text: ''
  expect(page).to have_css "[data-template-inputs-id='#{@report_template_1.id}'] #report_intro",       text: @report_template_1.intro
  expect(page).to have_css "[data-template-inputs-id='#{@report_template_1.id}'] #report_content",     text: @report_template_1.content
  expect(page).to have_css "[data-template-inputs-id='#{@report_template_1.id}'] #report_outro",       text: @report_template_1.outro
  expect {
    select 'Template 2', from: 'report_report_template_id'
  }.to change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}']", visible: true }.from(true)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}'] #report_name[disabled]",        visible: false}.from(false)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}'] #report_description[disabled]", visible: false}.from(false)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}'] #report_intro[disabled]",       visible: false}.from(false)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}'] #report_content[disabled]",     visible: false}.from(false)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_1.id}'] #report_outro[disabled]",       visible: false}.from(false)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_2.id}']", visible: true }.from(false)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_2.id}'] #report_name[disabled]",        visible: false}.from(true)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_2.id}'] #report_description[disabled]", visible: false}.from(true)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_2.id}'] #report_intro[disabled]",       visible: false}.from(true)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_2.id}'] #report_content[disabled]",     visible: false}.from(true)
  .and change { page.has_css? "[data-template-inputs-id='#{@report_template_2.id}'] #report_outro[disabled]",       visible: false}.from(true)
  expect(page).to have_css "[data-template-inputs-id='#{@report_template_2.id}'] #report_name",        text: @report_template_2.name
  expect(page).to have_css "[data-template-inputs-id='#{@report_template_2.id}'] #report_description", text: ''
  expect(page).to have_css "[data-template-inputs-id='#{@report_template_2.id}'] #report_intro",       text: @report_template_2.intro
  expect(page).to have_css "[data-template-inputs-id='#{@report_template_2.id}'] #report_content",     text: @report_template_2.content
  expect(page).to have_css "[data-template-inputs-id='#{@report_template_2.id}'] #report_outro",       text: @report_template_2.outro
  fill_in 'report_name',        with: 'newname'
  fill_in 'report_description', with: 'newdescription'
  fill_in 'report_intro',       with: 'newintro'
  fill_in 'report_content',     with: 'newcontent'
  fill_in 'report_outro',       with: 'newoutro'
  click_button 'Create Report'
  expect(page).to have_flash 'Report was successfully created.'
end

我知道这是一个丑陋的规格,但我注意到的是它需要大量的时间:大约 40 秒!

Finished in 41.86 seconds (files took 0.44731 seconds to load)

这是另一个激活了 JavaScript 的规范。虽然它要小得多(并且只发生一个完整的页面加载(,但我认为它所需的时间比上面的时间少得不成比例:

it 'allows to remove an existing finding', js: true, focus: true do
  visit edit_project_boilerplate_copy_path(@boilerplate_copy.project, @boilerplate_copy)
  click_link 'Remove finding'
  expect {
    click_button 'Update Boilerplate'
  } .to change { Finding.count }.by -1
end

大约需要 6-7 秒:

Finished in 6.62 seconds (files took 0.52104 seconds to load)

所以我想知道为什么第一个需要这么多时间。我的完整规格套件大约有 400 个规格,大约需要一分钟,所以通过添加新规格,它增加到近 2 分钟!这是不可接受的。

那么:如何改进我的JS规范?它与许多visible: false声明有关吗?还是许多and change { ... }的东西?也许两者在互动?

当删除所有带有visible: false的行时,它会更快:

Finished in 6.39 seconds (files took 0.41315 seconds to load)

我在OSX El Capitan上使用capybara(2.5.0(,rspec(3.3.0(,rails(4.2.1(和poltergeist(1.7.0(和phantomjs(1.9.8(。

你的测试太慢了,你遇到了水豚等待行为。 #has_css?/have_css将等待最多 Capybara.default_max_wait_time 秒,让匹配的元素出现在页面上,如果没有,则以 false 响应。 当您希望某个元素不在页面上时,您希望使用 #has_no_css?/have_no_css(或not_to #has_css?/have_css,因为它们最终是同一件事(,因为一旦找不到该元素,就会返回。

has_css?(....)  #will wait until element appears or default_max_wait_time
has_no_css?(....)  #will wait until element is gone or default_max_wait_time

基本上,在您的情况下,您不想将change匹配器与has_css一起使用,因为它不允许您使用在动作的每一侧尽快匹配的方法。 如果您真的想保留change匹配器,一个可能的选择是将一个小的等待值传递给has_css? wait: 0.5或会减少该项目的最大等待时间的东西,但可能需要进行调整以允许页面上发生的任何操作实际完成