3

I am trying to select an item in a SelectList element that is loaded dynamically.

I'm using a wait_until like so:

select_list(:oem, :id => 'oem_1')

def wait_for_oem(oem_name)
  self.oem_element.wait_until(20) do
    self.oem_options.include? oem_name
  end
end

This works great when my list only has a few items. Unfortunately, my list sometimes has 3000 items. When this happens, the above wait takes a few minutes to return (even though the list only takes a few seconds to populate).

I also tried:

def wait_for_oem(oem_name)
  self.oem_element.wait_until(20) do
    self.oem_options.length > 1
  end
end

That wasn't any better, I can put in a sleep 5 to work around the issue, but I'd prefer to avoid that.

Can you suggest wait options with better performance?

garrmark
  • 89
  • 1
  • 10
  • If you have any design input on the project, consider asking for an ajax lookup in a text field (like the search box on this site) so people can work more efficiently with your program. It seems to me if your option list has thousands of entries, it's not going to be something people want to interact with on a daily basis. – Elijah Sarver Feb 26 '14 at 16:44
  • @Elijah I hear you, we usually have this dynamic list filtered down to a handful of entries, this is just a "filter off" situation. – garrmark Feb 26 '14 at 17:03

2 Answers2

3

I believe the largest cost is retrieving all 3000 options, which is what the page object gem does when calling oem_options. By directly locating that specific option, you should get a performance gain.

There does not appear to be a way to directly locate options in the page object gem. Therefore, you will need to directly access the underlying selenium/watir methods.

In Watir-Webdriver:

def wait_for_oem(oem_name)
  self.oem_element.wait_until(20) do
    self.oem_element.element.option(:text => oem_name).exists?
  end
end  

In Selenium-Webdriver:

def wait_for_oem(oem_name)
  self.oem_element.wait_until(20) do
    begin
      self.oem_element.element.find_element(:xpath => "./option[text()=#{oem_name}]")
    rescue
      false
    end
  end
end  

Using the above methods to check a select list with 3000 options, reduced the time from 86 seconds to 0.25 seconds.

Justin Ko
  • 46,526
  • 5
  • 91
  • 101
  • Thanks for the response, I'm not seeing much of an improvement with the above method. I believe it has to do with the location of the option ([2129]) and the length of my option text (search string is 35 characters and the options are up to 75 characters). Searching by value improves the performance some, since my value is only 5 or 6 characters, but I'm still seeing 10 to 20 second wait times. I'm using **Selenium-Webdriver** and **Firefox 27.0.1**. – garrmark Feb 25 '14 at 14:40
  • Just to verify, are you saying the performance has improved a lot (since you initially reported the problem taking minutes and now it is seconds)? Can you give an example of the couple of options so I can try benchmarking alternative solutions? – Justin Ko Feb 25 '14 at 14:57
  • the improvement is only when I switch to using value e.g. **option[@value='17061']** Some examples of option text: **** – garrmark Feb 26 '14 at 15:58
2

You could set up an element inside your select list and test for its existence:

select_list(:oem, :id => 'oem_1')

And inside your wait:

wait_until(10, 'wait for oem option') do
  oem_element.selected_options.size > 0
end

Does that work better, or does it still try and scan all objects?

ETA: It also depends on whether you're using watir-webdriver or selenium-webdriver as your back-end for performance, at least where cheezy's object is concerned:

watir-webdriver:

def select(value)
  element.select(value)
end

selenium-webdriver:

def select(value)
  find_options.find do |option|
    option.text == value
  end.click
end

The main reason for this, when you dig into watir, is that watir uses an xpath it generates to selection the option more efficiently, and selenium appears to provide no such option at the select level.

Elijah Sarver
  • 587
  • 6
  • 8
  • Are you sure there is an `option` accessor and `option_element` method? I get an undefined method error and could not find them in the documentation. – Justin Ko Feb 26 '14 at 14:12
  • Yeah, I screwed that up. I'll edit the above with a somewhat-working solution. – Elijah Sarver Feb 26 '14 at 15:31
  • I tried something similar with waiting for an option by position in the list (the list starts out with one option, then is updated with the rest). I got an error when trying to select the option I wanted after the wait. I think I need to wait on the actual option being there. – garrmark Feb 26 '14 at 16:05
  • Added an explanation of why this might be slow. – Elijah Sarver Feb 26 '14 at 16:56