Joshua Muheim February 2016

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

While creating some JavaScript functionality in Rails, I use some ugly Capybara specs to help me assuring everything works. One of these specs looks like this:

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",       t        

Answers


Tom Walpole February 2016

Your test is so slow becauase you're running into Capybaras waiting behavior. #has_css?/have_css will wait up to Capybara.default_max_wait_time seconds for matching elements to appear on the page before responding with false if they don't. When you expect an element not to be on the page you want to be using #has_no_css?/have_no_css (or not_to #has_css?/have_css since they end up being the same thing) since that will return as soon as the element is not found.

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

Basically in your case, you don't want to be using the change matcher with has_css? because it doesn't allow you to use the method that will match as soon as possible on each side of the action. If you really want to keep the change matcher a potential option is to pass a small wait value to has_css? wait: 0.5 or something which will decrease the max wait time for that item, but may need to be tweaked to allow for whatever actions occur on the page to actually complete

Post Status

Asked in February 2016
Viewed 1,105 times
Voted 5
Answered 1 times

Search




Leave an answer