Capybara/Selenium: Speeding up Dropdown Selecting? - selenium

So this is a bit of a performance question regarding Selenium Webdriver (Chromedriver) and Capybara.
I have some react-select dropdowns with quite a bit of data in them. For some reason the react-selects take a VERY VERY long time to pick out the option in them. The code is pretty simple and I grabbed it from here: https://github.com/JedWatson/react-select/issues/832
But it basically comes down to:
page.find('.Select-control').click
page.find('.Select-option', text: 'the text').click
Thing is, this works fine. But it takes an extremely long time (Upwards of a minute a dropdown). Now...in Capybaras defense these dropdowns have a LOT of options to select from, so I thought selecting from the top-most item would be the fastest, but that doesn't seem to affect it.
Does Capybara/Selenium hold the "options" in a different sorted list somewhere or something? Since i'd assume selecting from a top option in the dropdown would be faster, but it doesn't seem to be?

Generally, when using the text option, find first finds all the elements that match using the locator with the current selector type. In your case your selector type is defaulting to :css, and the locator is .Select-option. So Capybara will find all elements with the class Select-option and then it will go through each of those elements comparing the text to see what matches (and checking visibility), but it will have to compare all of them to make sure the selector isn't ambiguous.
One way to speed that up would be to use first with a minimum option
page.first('.Select-option', text: 'the text', minimum: 1).click
which can skip some of the text and visibility checking since it doesn't have to worry about ambiguous elements. Another solution would be to skip the text option altogether and write it into an XPath along the lines of
page.find(:xpath, XPath.css('.Select-option')[XPath.string.n.is('the text')]).click # Haven't verified this is 100% correct but it should be close
If you're doing this a lot in your app you may want to consider creating a custom selector for this
Capybara.add_selector(:react_option) do
xpath do |locator|
XPath.css('.Select-option')[XPath.string.n.is(locator)]
end
# You can add other filters in here - see https://github.com/teamcapybara/capybara/blob/master/lib/capybara/selector.rb
end
which would then allow you to do
page.find(:react_option, 'the text').click
Note, if you can limit the element types it will also make the query more efficient, so if all of the elements are <li> elements you might want to do something like
XPath.css('li.Select-option')[XPath.string.n.is(locator)]

Related

How to write xpath for following example?

For example, I have div tag that has two attributes.
class='hello#123' text='321#he#321llo#321'
<div> class='hello#123' text='321#he#321llo#321'></div>
Here, I want to write xpath for both class and text attributes but numbers may change dynamically. ie., "hello#123" may become "345" when we reload. "321#he#321llo#321" may become "567#he#456llo#321".
Note: Need to write xpath in single line not separately.
Assuming that you have the (corrected) two-attribute-HTML
<div class='hello#123' text='321#he#321llo#321'>...</div>
you can select it using the following, for example:
Using the contains() function
//div[contains(#class,'hello') and contains(#text,'#he#')]
This is quite specific and only applicable if the "hello" is always split in the same way
Using the translate() function to mask everything except the chars for "hello"
//div[translate(#class,'#0123456789','')='hello' and translate(#text,'#0123456789','')='hello']
This removes all # chars and digits and checks if the remaining string is "hello"
I guess combining these two approaches you will be able to create your own XPath expression fitting your needs. The patterns you provided were not fully clear, so this may only approach a good enough solution.

How to find the reasoning behind IntelliJ Kotlin lint check

I received a lint message while writing Kotlin using IntelliJ as my IDE: The argument can be converted to 'Set' to improve performance
My code went something like this:
val variable3 = variable1 - variable2 variables are of type List<Int>
The linter recommended me to change it to val variable3 = variable1 - variable2.toSet()
I would like to find out why it recommends this change and where the documentation is so next time I can look up the messages and learn the reasoning behind the lint check.
This is about performance and efficiency — in particular, about how the performance scales as your data gets bigger.
The - operator calls the standard library's Iterable<T>.minus(elements: Iterable<T>) extension function. If you look at its code (which you can do in IntelliJ), you'll see that that works by taking the first iterable (variable1 in this case) and filtering it to keep only the values not in the second one (variable2).
How does it check whether an element is in the second one? By calling its contains() method. But how that works will depend on the type of iterable. Most Sets, for example, can look up by hash code, which takes a short time, regardless of how big the set is.
However, most Lists and other iterables can't do that: they need to search through the whole list, element by element. How long that takes will obviously depend on the size of the list — it'll be very quick for short lists, but it might take some time to search through a list with thousands or millions of elements.
What makes it particularly important in this case is that it has to do that search repeatedly: once for each element of the first one. So the time can really mount up.
Say that the first iterable has 𝐌 elements, and the second has 𝐍. The subtraction has to make 𝐌 checks; if the second one is a set, then each check takes about the same time, so the overall time is proportional to 𝐌. But if not, then each check will take time proportional to 𝐍, so the overall time is 𝐌×𝐍 — which can get very big very fast! (For example, if you make each list 10× bigger, it'll take 100× as long.)
So if you don't want your program to grind to a halt when it starts handling more data, it can be well worth converting the second list to a set first. For small amounts of data, it adds a little extra work, but that probably won't be noticeable; and for large amounts of data, it can be a really big win.
That's why the IntelliJ inspection suggests it.
(For those of you who know about algorithmic complexity, please forgive the simplifications I've made here :)
Interestingly, when I tried it myself (in IntelliJ 2021.2.3 with Kotlin v1.5.73), it didn't make that suggestion. And looking into that implementation of the standard library, I see that in some cases the minus() method will do the conversion for you! However, I think it doesn't cover some other common cases, so it's still worth doing the conversion yourself if you think the lists could get big.
You can hover over and open the documentation like this:
The general quick fix options can be found and turn on/off under
settings -> inspections -> kotlin (example)

request yadcf AND vs OR option for multi_select

Searching for an answer I found ambiguous multi_select filter - AND and OR condition - javascript and looked in the code. I don't see any way to have the multi_select support AND (intersection) and OR (union, the default).
Consider the Tags column in http://yadcf-showcase.appspot.com/DOM_source_select2.html. I would like to see a checkbox, or better a toggle button (not sure the best text, maybe AND and OR as defaults, but even better if the text is configurable) to set behavior.
In this case, assume Tags is multi_select and set to Tag1, Tag2. AND function would show only first two rows. OR function (default) would show all rows except 7 and 10.
I'm not sure this could be achieved with multi_select_custom_func as I'm not sure how to implement the toggle button.
Right now you can use only one AND / OR but not both (with the help of multi_select_custom_func) , but you can open an enhancement request asking for adding checkbox (with configurable label) which will allow you to implement different logic when checked / unchecked inside your multi_select_custom_func implementation

selecting first span value from a group in selenium

I would want to select the first instance of an element in a page where many number of such elements are present with 'ID' which will not be same always.
for example, visit, http://www.sbobet.com/euro which lists lot of sports and odds, where I want to click on the first odds.
and the html structure would be like this,
I want to click on this first span value and proceed with some test case.
Any help on how to achieve this ?
There could be two approaches two the problem:
1. If you are sure you will always need only the first instance:
driver.FindElementsByClassName("OddsR")[0];
If not, then you have collection of elemets and you can access an of those
2. Also, you can first identify any closest enclosing div and then you can use the same snippet as above:
driver.FindElementsByClassName("OddsR")[0];
This one is a better approach if page is a bit dynamic in nature
Use #class attribute. If OddsR class you are intrested in is the 1st one on the page then just use Driver.FindElement(By.ClassName("OddsR")). Webdriver will pick the 1st occurence (no matter if there are more)
Have checked your link and I agree with alecxe, you should probably start with div. But i would suggest a simpler selector :
css = "div.MarketBd span.OddsR"
The above selector will always point to the first span of "OddsR" class within div of "MarketBd" class.
Thanks for the response.
I am finally able to click on the element, by this XPATH,
"//span[#class='OddsR']"
This clicks on the first occurrence of 'OddsR' values, without giving any index.

Browser performance. Which way is better: $('#item1 img[src]').qtip( {..}); -vs- $('#item1').qtip( {..});?

Which way is better: $('#item1 img[src]').qtip( {..}); -OR- $('#item1').qtip( {..}); ?
It works both ways. Would you recommend to use img[src] as a part of the selector? Is it normal?
Thank you.
Those are two separate things:
$('#item1 img[src]').qtip( {..});
Selects an image element within an element with id item1.
$('#item1').qtip( {..});
Selects an element with id item1.
Also
What does img[src] do?
I only know that format when adding a src to it. Otherwise it does just nothing if it works.
$('img[src*="you_src_you_want_to_select"]')
With Sizzle in jQuery 1.3.x+, selects are performed from outer to inner (bottom to top, or right to left). jQuery is optimized for finding by ID, so by descending from an ID and adding more specific matching rules on the right without being overly specific, it is fair to say that you may see performance improvements.
I recommend checking out this presentation by Paul Irish for more details on selector performance:
http://paulirish.com/2009/perf/