How to upload a file with watir and IE? - ruby

I am writing a watir script to test an upload form.
But the script does not automatically choose the file that is to be uploaded from my harddrive.
Instead IE stops with the file chooser dialog open. As soon as I manually select the to be uploaded file in the dialog and click ok, watir continues as desired. I wonder why it stops.
This is my watir script:
require 'test/unit'
require 'watir'
# runs on win3k, IE 6.0.3790; ruby 1.8.6, watir
class EpcHomePage < Test::Unit::TestCase
def test_upload
ie = #browser
htmlfile = "C:\\testing\\upload.html"
uploadfile = "C:\\testing\\upload.html"
ie.goto(htmlfile)
ie.file_field(:name,"file1").set(uploadfile)
assert_equal uploadfile, ie.file_field(:name,"file1").value
ie.button(:name, 'upload').click
end
def setup
#browser = Watir::IE.new
end
def teardown
#browser.close
end
end
I got the code from this page: http://wiki.openqa.org/display/WTR/File+Uploads
This is the form:
<html><body>
<form name="form1" enctype="multipart/form-data" method="post" action="upload.html">
<input type="file" name="file1">
<input type="submit" name="upload" value="ok">
</form>
</body></html>
I have found this manual http://svn.openqa.org/svn/watir/trunk/watir/unittests/filefield_test.rb also. I am using IE 6 and also IE 7for the testing.
Edit: I have uploaded my simple example here (3 files that live in c:\testing\ on my machines, just start the cmd file):
http://dl.dropbox.com/u/1508092/testing.rar
It fails on 3 different machines (all windows 2003, 2x IE 6 and 1 x IE 7). I have also changed the sleep time in the script c:\ruby\lib\ruby\gems\1.8\gems\watir-1.6.5\lib\watir\input_elements.rb from 1 second to 5 seconds, like suggested by Željko Filipin in his answer:
def set(path_to_file)
assert_exists
require 'watir/windowhelper'
WindowHelper.check_autoit_installed
begin
Thread.new do
sleep 5 # it takes some time for popup to appear
system %{ruby -e '
...
This is where it stops (please note that I did manually navigate to the directory in the file dialog once. From that point on IE always shows the open dialog with this directory, but that does not mean that the script selected the directory. I think it means that IE always shows the last directory where it left):
this is where it stops http://dl.dropbox.com/u/1508092/upload-dialog.JPG
Edit:
I found that that the ole32 code looks for the english title:
POPUP_TITLES = ['Choose file', 'Choose File to Upload']
I installed IE 7 english version now. Still no success. But I think it has something to do with the localization, because input_elements.rb searches the window titles. I wonder why it still fails now. This is the code from input_elements.rb:
class FileField < InputElement
INPUT_TYPES = ["file"]
POPUP_TITLES = ['Choose file', 'Choose File to Upload']
# set the file location in the Choose file dialog in a new process
# will raise a Watir Exception if AutoIt is not correctly installed
def set(path_to_file)
assert_exists
require 'watir/windowhelper'
WindowHelper.check_autoit_installed
begin
Thread.new do
sleep 2 # it takes some time for popup to appear
system %{ruby -e '
require "win32ole"
#autoit = WIN32OLE.new("AutoItX3.Control")
time = Time.now
while (Time.now - time) < 15 # the loop will wait up to 15 seconds for popup to appear
#{POPUP_TITLES.inspect}.each do |popup_title|
next unless #autoit.WinWait(popup_title, "", 1) == 1
#autoit.ControlSetText(popup_title, "", "Edit1", #{path_to_file.inspect})
#autoit.ControlSend(popup_title, "", "Button2", "{ENTER}")
exit
end # each
end # while
'}
end.join(1)
rescue
raise Watir::Exception::WatirException, "Problem accessing Choose file dialog"
end
click
end
end
The text "Choose file" now appears in the title of my new IE. Anything else that should be localized or changed here? I updated the screenshot to the english version.

I knew about that problem, and completely forgot! Go to input_elements.rb file in your gems directory, and add the title of the file upload window in your language to POPUP_TITLES (line 443).
Example:
before
POPUP_TITLES = ['Choose file', 'Choose File to Upload']
after
POPUP_TITLES = ['Choose file', 'Choose File to Upload', 'File upload in my language']

I installed windows xp in english now, and it works! (The error occured on a localised windows server 2003)
I guess it was the localisation issue. I will just run watir on the english computer from now on.

I had the same problem today (March1,2012) and landed here via Google.
Thanks Željko for pointing me in the right direction, however the solution of changing the [POPUP_TITLES] didn't work. In fact, this array seems not to exist anymore in the current version of the gem (watir-2.0.4), or maybe I just misread.
I solved the problem in watir-2.0.4/lib/watir/dialogs/file_field.rb:
Here, the various window and button titles are defined as regular expressions. Change the regexps in the following methods
open_button()
cancel_button()
file_upload_window()
to match your localized window names. After reloading the gem, it worked flawlessly.

I would suggest that you take a look at FileField#set in input_elements.rb (in your Ruby gems directory), and change sleep 1 to sleep 2 (or some higher number). I have noticed that on slower machines it takes more than a second for file upload pop up to appear.

#modal = #browser.driver.switch_to.alert #Switch to open windows modal
key_to_send = "C:\\Users\\singhku\\Calabash_doc.pdf" #Path and name of file
#modal.send_keys(key_to_send)
require 'win32ole'
wsh = WIN32OLE.new('Wscript.Shell')
wsh.AppActivate('Choose File to Upload') #Name of the modal that is open
wsh.SendKeys('{ENTER}')

Related

How do you open a zip file using watir-webdriver?

My test suite has a cucumber front end with a ruby backend, running the latest version of watir-webdriver and its dependencies atop the latest version of OSX. My cucumber environment is setup to execute in Firefox.
The export feature of our app creates a zip file but to test the import feature, I need the contents of the zip file.
My actual test needs to unpack that zip file and select the individual files in it for use in testing the import feature of our web application.
Can anyone point me to a reference that can help me figure out how to write that?
Based off my experience, you download this file the same way that a normal user might. So first off, you just click the download button or whatever and then can access the file wherever it is and check out its contents.
Assuming the downloads just go to your Downloads folder by default, there is some simple code you can use to select the most recently downloaded item:
fn = Dir.glob("~/Downloads/*.zip").max { |a,b| File.ctime(a) <=> File.ctime(b)}
Then just use the unzip shell command to unzip the file. No reason to add another gem into the mix when you can just use generic shell commands.
`unzip #{fn}`
Then, you'd use Dir.glob again to get the filenames of everything inside the unzipped files folder. Assuming the file was named "thing.zip", you do this:
files = Dir.glob("~/Downloads/thing/*")
If you want to files to be downloaded directly to your project folder, you can try this. This also prevents the popup from asking you if you really want to save the file which is handy. I think this still works but haven't used it in some time. The above stuff works for sure though.
profile = Selenium::WebDriver::Firefox::Profile.new
download_dir = Dir.pwd + "/test_downloads"
profile['browser.download.dir'] = download_dir
profile['browser.helperApps.neverAsk.saveToDisk'] = "application/zip"
b = Watir::Browser.new. :firefox, :profile => profile
I ended up adding the rubyzip gem at https://github.com/rubyzip/rubyzip
the solution is on that link but i modified mine a little bit. I added the following to my common.rb file. see below:
require 'Zip'
def unpack_zip
test_home='/Users/yournamegoeshere/SRC/watir_testing/project files'
sleep(5) #<--manually making time to hit the save download dialog
zip_file_paths = []
Find.find(test_home) do |path|
zip_file_paths << path if path =~ /.*\.zip$/
end
file_name=zip_file_paths[0]
Zip::File.open(file_name) do |zip_file|
# Handle entries one by one
zip_file.each do |entry|
# Extract to file/directory/symlink
puts "Extracting #{entry.name}"
entry.extract(test_home + "/" + entry.name)
# Read into memory
content = entry.get_input_stream.read
end
# Find specific entry
entry = zip_file.glob('*.csv').first
puts entry.get_input_stream.read
end
end
This solution works great!

how to reload external file every time?

I have a ruby script where my "config" is in an extra file. It's called ftp_config.rb. Then I have filetrack.rb that downloads files from a ftp server - what files/directories is specified in ftp_config.rb. And finally I got rufus_download.rb that is calling a function from filetrack.rb every day so I get all new files from the server.
Everything works fine just I want to know how to make it so when I edit ftp_config.rb the changes are picked up by the script without the need to restart rufus_download.rb.
currenly
rufus_download.rb contains require_relative 'filetrack'
filetrack.rb contains require_relative 'ftp_config'
Right now if I add new files to be downloaded to ftp_config.rb I need to restart rufus
require_relative returns false if the file you have requested is already loaded to your ruby script and returns true if you haven't
If you want changes to be loaded directly you need to load files
load 'path/to/ftp_config'
every time your script executes it will load / reload the script
EDIT:
you can load by expanding path of the current ruby script:
load ::File.expand_path('../ftp_config.rb', __FILE__)
Assuming that files are in the same folder
EDITEND
hope that helps
You need a gem that monitors filechanges like "sinatra/reloader" for Sinatra and eg filewatcher or listen for desktop apps. After detecting an update you load the script, not require, that only loads a script once.
Here an example of filewatcher.
STDOUT.sync = true
FileWatcher.new(['c:/test/scans']).watch() do |filename, event|
puts filename
if(event == :changed)
puts "File updated: " + filename
end
if(event == :delete)
puts "File deleted: " + filename
end
if(event == :new)
puts "Added file: " + filename
end
end

Open URLs from CSV

I am using Ruby 2.1.0p0 on Mac OS.
I'm parsing a CSV file and grabbing all the URLs, then using Nokogiri and OpenURI to scrape them which is where I'm getting stuck.
When I try to use an each loop to run through the URLs array, I get this error:
initialize': No such file or directory # rb_sysopen - URL (Errno::ENOENT)
When I manually create an array, and then run through it I get no error. I've tried to_s, URI::encode, and everything I could think of and find on Stack Overflow.
I can copy and paste the URL from the CSV or from the terminal after using puts on the array and it opens in my browser no problem. I try to open it with Nokogiri it's not happening.
Here's my code:
require 'rubygems'
require 'nokogiri'
require 'open-uri'
require 'uri'
require 'csv'
events = Array.new
CSV.foreach('productfeed.csv') do |row|
events.push URI::encode(row[0]).to_s
end
events.each do |event|
page = Nokogiri::HTML(open("#{event}"))
#eventually, going to find info on the page, and scrape it, but not there yet.
#something to show I didn't get an error
puts "open = success"
end
Please help! I am completely out of ideas.
It looks like you're processing the header row, where on of those values is literally "URL". That's not a valid URI so open-uri won't touch it.
There's a headers option for the CSV module that will make use of the headers automatically. Try turning that on and referring to row["URL"]
I tried doing the same thing and found it to work better using a text file.
Here is what I did.
#!/usr/bin/python
#import webbrowser module and time module
import webbrowser
import time
#open text file as "dataFile" and verify there is data in said file
dataFile = open('/home/user/Desktop/urls.txt','r')
if dataFile > 1:
print("Data file opened successfully")
else:
print("!!!!NO DATA IN FILE!!!!")
exit()
#read file line by line, remove any spaces/newlines, and open link in chromium-browser
for lines in dataFile:
url = str(lines.strip())
print("Opening " + url)
webbrowser.get('chromium-browser').open_new_tab(url)
#close file and exit
print("Closing Data File")
dataFile.close()
#wait two seconds before printing "Data file closed".
#this is purely for visual effect.
time.sleep(2)
print("Data file closed")
#after opener has run, user is prompted to press enter key to exit.
raw_input("\n\nURL Opener has run. Press the enter key to exit.")
exit()
Hope this helps!

Cucumber no output screen

I'm pretty new to cucumber automated testing. When I first started, a co-worker had set up everything for me on my computer, and (now that he's gone) I've run into a problem that I can't seem to figure out.
I'm using cucumber to test a web application. In the past when I run the script, an internet explorer pops up, and I can see each line of the script being executed.
I recently had to reinstall cucumber, ruby, watir, etc., and that internet explorer screen no longer pops up.
I installed Ruby 1.9.3, cucumber (gem install cucumber), watir (gem install watir). Am I missing something? Is it an extra plug in? The script still runs. However, instead of taking say 1 min + to run a 320 step script, it now takes 1.5 seconds. There are no error messages. When run from the command window, it literally looked like it just scrolled through the script instead of going through each step.
What is the pop up screen called anyways? A scenario screen? Output screen?
It was really difficult for me to look it up on google because I had no idea how to refer to that screen.
Any help is appreciated. and I realize I might not have described the problem well enough. Just leave a comment, and I can try to clarify it more.
Feature:
'To go to a webpage'
Scenario:
# ----------
# GO TO PAGE
# ----------
Given that I have gone to the Login page at "url"
#
# ----------
# LOG IN
# ----------
When I add "username" to the Username
When I add "password" to the Password
And click the Login button
Then "Welcome" should be mentioned on the page
script definitions:
require "rubygems"
require "watir"
puts "Browser is running..."
END {
puts "Closing browser..."
}
BEGIN {
puts "Starting browser..."
}
Given /^that I have gone to the Login page at "(.*)"$/ do |item|
#browser = Watir::IE.start(item)
lnk_found = 0
#browser.links.each do |lnk|
if lnk.id.to_s.matches("overridelink")
lnk_found += 1
end
end
if lnk_found > 0
#browser.link(:id, "overridelink").click
end
# puts "Watir Version: #{Watir::IE::VERSION}"
#browser.maximize
end
#
#
#
When /^I add "(.*)" to the Username$/ do |item|
#browser.text_field(:name, "loginName").set(item)
end
#
#
When /^I add "(.*)" to the Password$/ do |item|
#browser.text_field(:name, "passwd").set(item)
end
#
#
#
Then /^"(.*)" should be mentioned on the page$/ do |item|
if #browser.text.include?(item)
# puts "TEST PASSED. FOUND >#{item}<"
else
puts "*** TEST FAILED ***. >#{item}< was not found."
end
end
Directory Structure
Cucumber
Testing
lib
login.rb
login.feature
I don't know what exactly fixed it but after taking suggestions and advices from different people I basically uninstalled and reinstalled watir several times.
I also updated the code, took out "require 'rubygems'" and replaced Watir::IE.start with Watir::Browser.start.
It seems like the problem was the existing scripts I worked with was based off of older versions of watir/cucumber/ruby, so when I had to reinstall everything, the scripts were no longer compatible with newer versions of everything.

How to upload a file with watir and Internet Explorer?

Over the last couple of days i have been put in charge of Automating certain aspects of my companies CMS systems. (We are using Drupal)
One of the issue i am having with my ruby script is getting IE to select a local file from my machine and adding it to my submit form.
Now i have been reading up about this and found a few simular posts, but the different with the form we are using is that the browse button is made out of flash and there is no input field for the file path. The options i have is to either type in the "File Name" and clicks the "Open" button or the second option is to double click a file.
So they way i have got round this so far is to tab down to the "browser button and then press the "Enter" key to open the browse menu. But i now need the ability to select a file name.
This is my Ruby File.
require 'watir'
include Watir
ie = Watir::IE.new
ie.goto ("file:///C:/Ruby193/bin/ruby-capybara/features/step_definitions/form.html")
ie.text_field(:id, "edit-submitted-ugc-video-title").set("Title")
ie.text_field(:id, "edit-submitted-ugc-video-firstname").set("First Name")
ie.text_field(:id, "edit-submitted-ugc-video-lastname").set("Last Name")
ie.text_field(:id, "edit-submitted-ugc-video-phonenumber").set("01234567891")
ie.text_field(:id, "edit-submitted-ugc-video-location").set("London")
ie.text_field(:id, "edit-submitted-ugc-video-email").set("test#test.com")
ie.text_field(:id, "edit-submitted-ugc-video-email2").set("test#test.com")
ie.send_keys('{TAB}')
ie.send_keys('{ENTER}')
uploadfile = "V:\GIR-FP-WSD-QA\Test Media Files\Video1.mp4"
assert_equal uploadfile, ie.file_field(:name,"Video1.mp4").value
ie.button(:name, 'upload').click
#
Edited:
require 'watir'
require 'win32ole'
include Watir
ie = Watir::IE.new
ie.goto ("file:///C:/Ruby193/bin/ruby-capybara/features/step_definitions/form.html")
ie.text_field(:id, "edit-submitted-ugc-video-title").set("Title")
ie.text_field(:id, "edit-submitted-ugc-video-firstname").set("First Name")
ie.text_field(:id, "edit-submitted-ugc-video-lastname").set("Last Name")
ie.text_field(:id, "edit-submitted-ugc-video-phonenumber").set("01234567891")
ie.text_field(:id, "edit-submitted-ugc-video-location").set("London")
ie.text_field(:id, "edit-submitted-ugc-video-email").set("test#test.com")
ie.text_field(:id, "edit-submitted-ugc-video-email2").set("test#test.com")
ie.send_keys('{TAB}')
ie.send_keys('{ENTER}')
class FileField < InputElement
# set the file location in the Choose file dialog in a new process
# will raise a Watir Exception if AutoIt is not correctly installed
def set(setPath)
assert_exists
require 'watir/windowhelper'
WindowHelper.check_autoit_installed
begin
thrd = Thread.new do
system("rubyw -e \"require 'win32ole'; #autoit=WIN32OLE.new('AutoItX3.Control');
waitresult=#autoit.WinWait 'Bird annoys Cat.mp4', '', 15; sleep 1; if waitresult == 1\" -e
\"#autoit.ControlSetText 'Bird annoys Cat.mp4', '', 'Edit1', '#{setPath}';
#autoit.ControlSend 'Bird annoys Cat.mp4', '', 'Button2', '{ENTER}';\" -e \"end\"")
end
thrd.join(1)
rescue
raise Watir::Exception::WatirException, "Problem accessing Choose file dialog"
end
click
$end
ie.button(:name, 'upload').click
I'm afraid in this situation you have to use windows automation.
It may be either winapi or some sort of automation framework, for example autoit:
class FileField < InputElement
# set the file location in the Choose file dialog in a new process
# will raise a Watir Exception if AutoIt is not correctly installed
def set(setPath)
assert_exists
require 'watir/windowhelper'
WindowHelper.check_autoit_installed
begin
thrd = Thread.new do
system("rubyw -e \"require 'win32ole'; #autoit=WIN32OLE.new('AutoItX3.Control');
waitresult=#autoit.WinWait 'Choose file', '', 15; sleep 1; if waitresult == 1\" -e
\"#autoit.ControlSetText 'Choose file', '', 'Edit1', '#{setPath}';
#autoit.ControlSend 'Choose file', '', 'Button2', '{ENTER}';\" -e \"end\"")
end
thrd.join(1)
rescue
raise Watir::Exception::WatirException, "Problem accessing Choose file dialog"
end
click
end
end
Automating stuff done in flash is sometimes a pretty big pain due to how proprietary it is. You may want to look into using an image based automation method for this section of the test. See this blog posting for more info
Is the file selection dialog native Windows File Open Dialog or is that also proprietary flash solution?
If it is native dialog (e.g. same as in everywhere else) then you can use my library RAutomation or autoit as suggested above.
If that's the case, then you could take some hints how to do that from Watir's code.
Also, does that flash upload have some JavaScript API? If that's the case then you could use #execute_script to do all the things you need - e.g. set the file programmatically and move on. I'm doing something similar with flash video player.

Resources