watir-webdriver setting value to text_field very slow - ruby

It takes around 4-5 seconds to set large text to text_field using watir-webdriver. I have also tried value method, but still it's very slow.
I have found a workaround for this on Windows using Clipboard gem and send_keys [:control, "v"], however this does not really work with headless linux. Any suggestion on this?

Inputting large values can be slow because the characters are inputted one at a time. This is to trigger each of the key events.
Assuming your application does not care about the events triggered by inputting the field, you could directly set the value via JavaScript.
Watir 6.8+
Watir now provides a #set! method to do this:
long_text = "abcde fghijk lmnop qrstuv"
browser.text_field.set!(long_text)
Pre-Watir 6.8
Prior to v6.8 (when this was originally answered), this needed to be done manually via #execute_script:
long_text = "abcde fghijk lmnop qrstuv"
the_field = browser.text_field
p the_field.value
#=> ""
browser.execute_script("arguments[0].value = '#{long_text}';", the_field)
p the_field.value
#=> "abcde fghijk lmnop qrstuv"
Performance Comparison
Even with this small text, you can see that execute_script is much faster. A benchmark:
n = 100
Benchmark.bm do |x|
x.report("execute_script:") { n.times { browser.execute_script("arguments[0].value = '#{long_text}';", the_field) } }
x.report("set:") { n.times { the_field.set(long_text) } }
end
The results:
user system total real
execute_script: 0.874000 0.609000 1.483000 ( 6.690669)
set: 2.199000 1.295000 3.494000 ( 22.384238)

Related

Ruby Zlib compression gives different outputs for the same input

I have this ruby method for compressing a string -
def compress_data(data)
output = StringIO.new
gz = Zlib::GzipWriter.new(output)
gz.write(data)
gz.close
compressed_data = output.string
compressed_data
end
When I call this method with the same input, I get different outputs at different times. I am trying to get the byte array for the compressed outputs and compare them.
The output is Different when I run the below -
input = "hello world"
output1 = (compress_data input).bytes.to_a
sleep 1
output2 = (compress_data input).bytes.to_a
if output1 == output2
puts 'Same'
else
puts 'Different'
end
The output is Same when I remove the sleep. Does the compression algorithm have something to do with the current time?
Option 1 - fixed mtime:
Yes. The compression time is stored in the header. You can use the mtime method to set the time to a fixed value, which will resolve your problem:
gz = Zlib::GzipWriter.new(output)
gz.mtime = 1
gz.write(data)
gz.close
Note that the Ruby documentation says that setting mtime to zero will disable the timestamp. I tried it, and it does not work. I also looked at the source code, and it appears this functionality is missing. Seems like a bug. So you have to set it to something else than 0 (but see comments below - it will be fixed in future releases).
Option 2 - skip the header:
Another option is to just skip the header when checking for similar data. The header is 10 bytes long, so to only check the data:
data = compress_data(input).bytes[10..-1]
Note that you do not need to call to_a on bytes. It is already an Array:
String.bytes -> an_array
Returns an array of bytes in str. This is a shorthand for str.each_byte.to_a.

Match Multiple Patterns in a String and Return Matches as Hash

I'm working with some log files, trying to extract pieces of data.
Here's an example of a file which, for the purposes of testing, I'm loading into a variable named sample. NOTE: The column layout of the log files is not guaranteed to be consistent from one file to the next.
sample = "test script result
Load for five secs: 70%/50%; one minute: 53%; five minutes: 49%
Time source is NTP, 23:25:12.829 UTC Wed Jun 11 2014
D
MAC Address IP Address MAC RxPwr Timing I
State (dBmv) Offset P
0000.955c.5a50 192.168.0.1 online(pt) 0.00 5522 N
338c.4f90.2794 10.10.0.1 online(pt) 0.00 3661 N
990a.cb24.71dc 127.0.0.1 online(pt) -0.50 4645 N
778c.4fc8.7307 192.168.1.1 online(pt) 0.00 3960 N
"
Right now, I'm just looking for IPv4 and MAC address; eventually the search will need to include more patterns. To accomplish this, I'm using two regular expressions and passing them to Regexp.union
patterns = Regexp.union(/(?<mac_address>\h{4}\.\h{4}\.\h{4})/, /(?<ip_address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/)
As you can see, I'm using named groups to identify the matches.
The result I'm trying to achieve is a Hash. The key should equal the capture group name, and the value should equal what was matched by the regular expression.
Example:
{"mac_address"=>"0000.955c.5a50", "ip_address"=>"192.168.0.1"}
{"mac_address"=>"338c.4f90.2794", "ip_address"=>"10.10.0.1"}
{"mac_address"=>"990a.cb24.71dc", "ip_address"=>"127.0.0.1"}
{"mac_address"=>"778c.4fc8.7307", "ip_address"=>"192.168.1.1"}
Here's what I've come up with so far:
sample.split(/\r?\n/).each do |line|
hashes = []
line.split(/\s+/).each do |val|
match = val.match(patterns)
if match
hashes << Hash[match.names.zip(match.captures)].delete_if { |k,v| v.nil? }
end
end
results = hashes.reduce({}) { |r,h| h.each {|k,v| r[k] = v}; r }
puts results if results.length > 0
end
I feel like there should be a more "elegant" way to do this. My chief concern, though, is performance.

FireWatir TextField set : Very Slow

When calling the set method of a text_field in ruby, the text is being entered at a very slow rate in the browser, roughly at 1 character / second.
Environment Information:
Ubuntu 10.10
FireFox 3.6.13
JSSh 0.9
Ruby 1.9.2p136
FireWatir 1.7.1
Kindly advice. Thanks in advance.
It is a known bug: WTR-397
Workaround is to use watir-webdriver or to use value= instead of set. Example:
browser.text_field(how => what).value= "string"
solve slow key type issue on firewatir:
need to edit the file text_field.rb
enter to the folder
#>cd /usr/lib/ruby/gems/1.8/gems/firewatir-1.7.1/lib/firewatir/elements/ make it writeable
#>chmod 777 text_field.rb edit the proc def doKeyPress( value )
put # in front of #o.fireEvent("onKeyDown") and #o.fireEvent("onKeyPress") and #o.fireEvent("onKeyPress")
instead enter fire_key_events
def doKeyPress( value )
begin
max = maxlength
if (max > 0 && value.length > max)
original_value = value
value = original_value[0...max]
element.log " Supplied string is #{suppliedValue.length} chars, which exceeds the max length (#{max}) of the field. Using value: #{value}"
end
rescue
# probably a text area - so it doesnt have a max Length
end
for i in 0..value.length-1
#sleep element.typingspeed # typing speed
c = value[i,1]
#element.log " adding c.chr " + c #.chr.to_s
#o.value = "#{(#o.value.to_s + c)}" #c.chr
fire_key_events #add this
##o.fireEvent("onKeyDown")
##o.fireEvent("onKeyPress")
##o.fireEvent("onKeyUp")
end
now it should work faster

Simplest way to display each hour of the day in Ruby

I have a calendar screen where I want to display the hours of the day like this:
12:00am
1:00am
2:00am
..
4:00pm
5:00pm
etc.
Being a total Ruby noob, I was wondering if anyone could help me figure out the simplest way to display this.
#!/usr/bin/env ruby
# without using actual `Date` objects ...
p ["12:00am"] + (1..11).map {|h| "#{h}:00am"}.to_a +
["12:00pm"] + (1..11).map {|h| "#{h}:00pm"}.to_a
["12:00am", "1:00am", "2:00am", "3:00am", "4:00am", "5:00am", "6:00am",
"7:00am", "8:00am", "9:00am", "10:00am", "11:00am", "12:00pm", "1:00pm",
"2:00pm", "3:00pm", "4:00pm", "5:00pm", "6:00pm", "7:00pm", "8:00pm",
"9:00pm", "10:00pm", "11:00pm"]
Or using actual DateTime objects and %I:%M%p as format:
#!/usr/bin/env ruby
require "Date"
for hour in 0..23 do
d = DateTime.new(2010, 1, 1, hour, 0, 0)
p d.strftime("%I:%M%p")
end
Which would print:
"12:00AM"
"01:00AM"
"02:00AM"
"03:00AM"
"04:00AM"
"05:00AM"
"06:00AM"
"07:00AM"
"08:00AM"
"09:00AM"
"10:00AM"
"11:00AM"
"12:00PM"
"01:00PM"
"02:00PM"
"03:00PM"
"04:00PM"
"05:00PM"
"06:00PM"
"07:00PM"
"08:00PM"
"09:00PM"
"10:00PM"
"11:00PM"
You could generate these like this:
array = ['12:00am'] + (1..11).map {|h| "#{h}:00am"} + ['12:00pm'] + (1..11).map {|h| "#{h}:00pm"}
or simply write out the array (this is more efficient):
array = ["12:00am", "1:00am", "2:00am", "3:00am", "4:00am", "5:00am", "6:00am", "7:00am", "8:00am", "9:00am", "10:00am", "11:00am", "12:00pm", "1:00pm", "2:00pm", "3:00pm", "4:00pm", "5:00pm", "6:00pm", "7:00pm", "8:00pm", "9:00pm", "10:00pm", "11:00pm"]
You can then print these however you want, eg.
array.each do |el|
puts el
end

Testing time critical code

I've written a feature for my library Rubikon that displays a throbber (a spinning — as you may have seen in other console apps) as long as some other code is running.
To test this feature I capture the output of the throbber in a StringIO and compare it with the expected value. As the throbber is only displayed as long as the other code is running the content of the IO gets longer when the code runs longer. In my tests I do a simple sleep 1 and should have a constant 1 second delay. This works most of the time, but sometimes (apparently due to external factors like heavy load on the CPU) it fails, because the code doesn't run for 1 second, but for a bit more, so that the throbber prints a few additional characters.
My question is: Is there any possibility to test such time critical features in Ruby?
From your github repository, I found this test for the Throbber class:
should 'work correctly' do
ostream = StringIO.new
thread = Thread.new { sleep 1 }
throbber = Throbber.new(ostream, thread)
thread.join
throbber.join
assert_equal " \b-\b\\\b|\b/\b", ostream.string
end
I'll assume that a throbber iterates over ['-', '\', '|', '/'], backspacing before each write, once per second. Consider the following test:
should 'work correctly' do
ostream = StringIO.new
started_at = Time.now
ended_at = nil
thread = Thread.new { sleep 1; ended_at = Time.now }
throbber = Throbber.new(ostream, thread)
thread.join
throbber.join
duration = ended_at - started_at
iterated_chars = " -\\|/"
expected = ""
if duration >= 1
# After n seconds we should have n copies of " -\\|/", excluding \b for now
expected << iterated_chars * duration.to_i
end
# Next append the characters we'd get from working for fractions of a second:
remainder = duration - duration.to_i
expected << iterated_chars[0..((iterated_chars.length*remainder).to_i)] if remainder > 0.0
expected = expected.split('').join("\b") + "\b"
assert_equal expected, ostream.string
end
The last assignment of expected is a bit unpleasant, but I made the assumption that the throbber would write character/backspace pairs atomically. If this is not true, you should be able to insert the \b escape sequence into the iterated_chars string and remove the last assignment entirely.
This question is similar (I think, altough I'm not completely sure) to this one:
Only real time operating system can
give you such precision. You can
assume Thread.Sleep has a precision of
about 20 ms so you could, in theory
sleep until the desired time - the
actual time is about 20 ms and THEN
spin for 20 ms but you'll have to
waste those 20 ms. And even that
doesn't guarantee that you'll get real
time results, the scheduler might just
take your thread out just when it was
about to execute the RELEVANT part
(just after spinning)
The problem is not rubby (possibly, I'm no expert in ruby), the problem is the real time capabilities of your operating system.

Resources