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

时间:2016-02-08 14:47:50

标签: javascript ruby-on-rails capybara

在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)。

1 个答案:

答案 0 :(得分:2)

你的测试是如此缓慢,因为你正在进入Capybaras等待行为。 #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

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