Ruby Selenium ActionBuilder send_keys method duplicating the strings I send - ruby

So let say I have an array called list that contains strings per below, when I loop through the array to send_keys each items from the array onto an online text editor element which already has focus:
list = ["First", "Second", "Third"]
for index in 0 ... list.size
line = list[index]
chain.send_keys(line).perform
if index < list.size
page.driver.browser.action.send_keys(:return).perform
end
end
The problem I'm facing is that instead of the output to look like this:
First
Second
Third
it instead looks like this:
First
First Second
First Second Third
Why is this happening ? is it because the previous actions are still in the action queue and have not cleared up ? or some other reason ? I'd appreciate if anyone can help.

When using the actions api it builds up a list of actions that are then executed by calling perform. Calling perform however doesn't reset that list, so if you call perform again it repeats the same actions. With the way you're calling it
chain.send_keys(line).perform
adds a send_keys action to chain - then performs it. Next time it adds another send_keys action to chain and then performs both actions. Solutions for that would be just create a new action chain each time rather than reusing chain or calling chain.clear_actions to clear the action chain each time through the loop.
What isn't clear though is why you're using the action API at all rather than just calling send_keys on the element you want to send the keys too
el = find(...) # find the element on the page you want to send the keys to
list.each do { |str| el.send_keys(str, :return) }

The way selenium sendkeys works is, the sendkeys commands sends the string value to the text element, It will not do any check whether is there any text present in it or not.
If you want to have the keys set newly for each time,
Please use the command chain.clear() before chain.send_keys(line).perform in the loop.
This will ensure the text in the element is cleared each time before the send_keys.
Let me know if this doesn't help you.
https://selenium-python.readthedocs.io/navigating.html#interacting-with-the-page

Related

how to call clear method on the element object

In my project I have located the text_Field via some other element(via label), something like
element.following_sibling(tag_name: 'input').send_keys 'something'
But now it's typing into the text_field without any problem but I am missing clear method of text_field as it combines both clear and type together. Now I have to call clear method on element.following_sibling(tag_name: 'input') but since it's returning element object, I couldn't do that. Is there any way I can call clear method here? Or can I pass this object by some way to the text_field() method? Any help appreciated.
I know it can be called by converting the watir element into selenium element as given below
element.following_sibling(tag_name: 'input').wd.clear
But here I am missing WATIR waiting time for an element.
This appears to be a limitation in Watir's adjacent methods:
klass = if !plural && opt[:tag_name]
Watir.element_class_for(opt[:tag_name])
elsif !plural
HTMLElement
elsif opt[:tag_name]
Object.const_get("#{Watir.element_class_for(opt[:tag_name])}Collection")
else
HTMLElementCollection
end
Notice that only the :tag_name is used for determining the element's class. For input elements, we need to also consider the type attribute so that we can the right sub-class.
We should fix this in Watir (logged as Issue 878), but in the mean time, you can manually correct the class (ie Watir::TextField) using #to_subtype:
element.following_sibling(tag_name: 'input').to_subtype.clear
I got an answer to my question now.
Here is the answer.
b.text_field(element: element.following_sibling(tag_name: 'input').wd).set 'something'
If anybody has any better idea, please write your answer.Thanks.

Ruby cucumber automation suite - parameter received as null while iterating

I inherited a test automation suite and while modifying it I am trying to write a function to test similar links which are present in the same web page but in different divs and the tag ids are dynamic.
I have a function defined below which accepts an HTML element and sends an action to the element
def element_do(html_element, html_element_type, html_element_value, action)
#browser.send(html_element.to_sym,html_element_type.to_sym ,html_element_value).send(action)
end
I have a method defined as somemethod and I am trying to call the method in a particular div using the some_element#{i} as below
def multiple_accounts
#num_accts.each do |i|
p "validating for account #{i}"
#page.element_do(:div,:id,"some_element#{i}",somemethod)
end
The issue I am facing is that on second iteration the action parameter is passed as null instead of the somemethod. I am new to ruby automation and I am not sure what exactly is happening. Any help is appreciated
Additional details - based on the questions
1) #num_accts is an array which is got by scanning the text of the webpage and contains account numbers (eg: [56544, 87990])
2) This forms a part of the id for the divs as in "acct#56544". So I am passing the array elements from num_accts to "acct#{i}" referred as 'some_element'
3) 'Somemethod' is a method defined to click on a particular link in the div and verifies a text to confirm that the link redirects to the correct page. The some method works fine when there is only one div.
It is not evident from the question, but my suspicion is that you try to pass the name of the method (which returns null), but instead you call the method. I think your call should be:
#page.element_do(:div,:id,"some_element#{i}",'somemethod')

Logstash: Handling a Configuration File for a Filter

I've written a filter and use its register-function to load an external CSV-file and fill a bunch of hash-tables. The filter-function then accesses the hash-tables and adds fields to the event. While that's working nicely, the downside is that it only loads once and I'd need to restart logstash to trigger the reload after a change in the CSV-file. Maybe I should add that the filter is currently consuming events coming from three different file inputs.
Writing an input doesn't seem to solve it as the input is not tied to the filter in some way. Therefore, my plan is to somehow reload the CSV-file every few hours or at a particular time and somehow block the entire filter during that, i.e. pause incoming events. That sounds like a weird thing to do and I'm not sure whether or not logstash is actually meant to be used like this.
I'm a newbie regarding Ruby and actually I'm quite amazed that the filter is working this nice. As Google let me down on the entire issue I'm hoping that anyone on here has experience with this, can post a link to an example or can point me to another way of solving this.
For educational purposes I looked into the source of logstash and noticed that I could actually understand what's going on and things are much less complicated than I had thought.
There is a function filterworker in pipeline.rb and a class filterworker and I don't know which one is actually used, but my findings seem to be true for both.
Basically all filters seem to run in one thread in case it's not configured otherwise. This means that I can reload the file anywhere in the filter-function and the entire processing for all filters is paused (input and output might still do something, but that's handled by the queue for the events holding maximum 20 entries).
Therefore, this seems to do it for me:
public
def register
#config_files_read_timestamps = {}
read_config_files
end # def register
def filter(event)
# return nothing unless there's an actual filter event
return unless filter?(event)
read_config_files
:
# filter_matched should go in the last line of our successful code
filter_matched(event)
end # def filter
private
def read_config_files
read_marker_file
:
end
def check_for_changed_file?(filename)
mtime = File.mtime(filename)
#config_files_read_timestamps[filename] ||= Time.at(0)
if #config_files_read_timestamps[filename] < mtime
#config_files_read_timestamps[filename] = mtime
return true
end
end
def read_marker_file
if !check_for_changed_file?("markers.txt")
return
end
:
end
Obviously I don't need a separate thread for the parsing. It would become necessary if I plan to start the reload at a specific time. In that case I'd have to join the thread and then continue with event handling.
Let me know if there could be improvements...

Split array into comma separated list of values

I'm working on a bit of metaprogramming using send methods quite a bit. I've been successful so far because the methods I'm sending to only take one argument.
Example:
client is an API client
#command is a method on client taken as an option to a CLI utility
#verb is a method on command taken as another option in the CLI
def command_keys
case #command
when "something"
self.command_options.slice(:some, :keys)
end
end
Then I call the API client like this:
client.send(#command).send(#verb, command_keys)
This works since the methods all take a Hash as their argument. The problem I've run into is when I need to send more than 1 parameter in command_keys. What I'm wondering is the best way to handle the command_keys method returning more than 1 value. Example:
def command_keys
case #command
when "something"
return self.command_options[:some], self.command_options[:keys]
end
end
In this case, command_keys returns an Array as expected, but when I try to pass that in the send(#verb, command_options) call, it passes it as an Array (which is obviously expected). So, to make a long story short, is there some easy way to make this condition be handled easily?
I know send(#verb, argument1, argument2) would get me the result I want, but I would like to be able to not have to give my script any more implementation logic than it needs, that is to say I would like it to remain as abstracted as possible.
Use splat. You might have to rethink the code a bit, but something like:
client.send(#command).send(#verb, *all_the_args)

PageObject with Ruby - set text in a text field only works in the main file

I'm automating a site that has a page with a list of options selected by a radio button. When selecting one of the radios, a text field and a select list are presented.
I created a file (test_contracting.rb) that is the one through which I execute the test (ruby test_contracting.rb) and some other classes to represent my page.
On my class ContractPage, I have the following element declaration:
checkbox(:option_sub_domain, :id => "option_sub_domain")
text_field(:domain, :id => "domain_text")
select_list(:tld, :id => "domain_tld")
I've created in the ContractPage a method that sets the configuration of the domain like this:
def configure_domain(config={})
check_option_sub_domain
domain = config[:domain]
tld = config[:tld]
end
When I call the method configure_domain from the test_contracting.rb, it selects the radio button, but it doesn't fill the field with the values. The params are getting into the method correctly. I've checked it using "puts". Even if I change the params to a general string like "bla" it doesnt work. The annoying point is that if on test_contracting.rb I call the exact same components, it works.
my_page_instance = ContractPage.new(browser)
my_page_instance.domain = "bla"
my_page_instance.tld = ".com"
What I found to work was to in the configure_domain method, implement the following:
domain_element.value = config[:domain]
tld_element.send_keys config[:locaweb_domain]
Then it worked.
The documentation for the PageObjects module that I'm using as reference can be found here: http://rubydoc.info/github/cheezy/page-object/master/PageObject/Accessors#select_list-instance_method
Do you guys have any explation on why the method auto generated by the pageobject to set the value of the object didnt work in this scope/context ?
By the way, a friend tried the same thing with Java and it failed as well.
In ruby all equals methods (methods that end with the = sign) need to have a receiver. Let me show you some code that will demonstrate why. Here is the code that sets a local variable to a value:
domain = "blah"
and here is the code that calls the domain= method:
domain = "blah"
In order for ruby to know that you are calling a method instead of setting a local variable you need to add a receiver. Simply change your method above to this and it will work:
def configure_domain(config={})
check_option_sub_domain
self.domain = config[:domain]
self.tld = config[:tld]
end
I'm pretty new to this world of Selenium and page objects but maybe one of my very recent discoveries might help you.
I found that that assignment methods for the select_list fields only worked for me once I started using "self" in front. This is what I have used to access it within my page object code. e.g., self.my_select_list="my select list value"
Another note - The send_keys workaround you mention is clever and might do the trick for a number of uses, but in my case the select list values are variable and may have several options starting with the same letter.
I hope something in here is useful to you.
UPDATE (Jan 3/12)
On diving further into the actual Ruby code for the page object I discovered that the select_list set is also using send_keys, so in actuality I still have the same limitation here as the one I noted using the send_keys workaround directly. sigh So much to learn, so little time!

Resources