I am using Watir-Webdriver with Firefox and the method recommended on the watirwebdriver.com site to automate file downloads. This involves setting FireFox about:config parameters to disable the download dialog in FireFox for specific file types. This works well but now I am trying to figure out how best to determine when the file download has completed (some take a few seconds, some take minutes) so I can logout of the site and move on to the next test. It seems since there are no visual clues left in the browser I may have to monitor the file in the download directory. Any options would be appreciated.
问题:
回答1:
Chrome stores uncompleted downloads with an added .crdownload
file extension. Check to see if the download directory has a file ending with .crdownload
and that should tell you if a download is still ongoing
回答2:
Maybe you can track the file size to see when it stops changing for a few seconds.
回答3:
I didn't like just looking at filesize, it felt fragile, so I ended up using the lsof command to detect when there are no processes holding the file open, and then reading the file. It's better in that a pause in the download due to network hiccups won't cause intermittent errors, but worse(?) in that it is not portable and shells out to the lsof command.
The coded looked something like this:
# Watch the download dir for new files, and read the first new file that
# appears.
def read_newest_download
existing_files = list_files_in_download_dir
new_files = []
Timeout::timeout(DOWNLOAD_TIMEOUT) do
while (new_files = list_files_in_download_dir - existing_files).empty?
sleep 0.25
end
end
if 1 == new_files.size
wait_for_file_to_be_closed(new_files.first)
File.read(new_files.first)
else
fail "Found #{new_files.size} new files."
end
end
# Ignore files ending in .part, which is common for temp files in Firefox.
def list_files_in_download_dir
raise ArgumentError, "No download dir specified" unless @opts[:download_dir]
@_download_glob ||= File.join(@opts[:download_dir], "*")
# Ignore files ending in .part as they're temporary files from Firefox.
Dir[@_download_glob].entries.reject {|e| /\.part$/ === e}
end
def wait_for_file_to_be_closed(filename)
begin
sleep 0.25
end until `lsof #{filename}`.blank?
end
回答4:
I had a similar task where I wanted to extract the contents of a downloaded PDF file. I used to following solution:
t = ''
(0..19).each do
sleep 5
t = `pdftotext -raw some_directory/*.pdf -`
break if $?.success?
end
It does 20 attempts at extracting the text using the shell command pdftotext and will break out of the block if the shell command was successful. The advantage of doing it this way is that if the file doesn't exist or if the file is only partially downloaded it will produce an error and then try again. If your file is not a PDF or you don't care about the contents then you use another shell command instead of pdftotext, so long as it produces an error if the file is incomplete.
回答5:
I have a bit different approach for file-downloads automation. I do it like this:
The requiures:
require 'rubygems'
require 'watir-webdriver'
require 'win32ole'
First create a method for the Filesize handling:
def fileinfo(name)
if File.exists?(name)
print "#{name} exists "
bytes = File.size(name)
print "and is #{bytes} in size;"
whenm = File.mtime(name)
print whenm,";"
print whenm.to_i,";"
else
print "#{name} does NOT exist;"
end
end
Secondly drive chrome with pre set-up download dir:
download_directory = "#{Dir.pwd}/downloads"
download_directory.gsub!("/", "\\") if Selenium::WebDriver::Platform.windows?
profile = Selenium::WebDriver::Chrome::Profile.new
profile['download.prompt_for_download'] = false
profile['download.default_directory'] = download_directory
Next delete the file (from previous runs) for test case re-usability and validness (one of 3):
%x(DEL /Q C:\\automation\\qa\\downloads\\*.exe)
%x(DEL /Q downloads\\*.exe)
%x(DEL /Q downloads\\*.*)
Define the size variable of the downloaded component:
contains = Dir.new(download_directory).entries
dlc = contains[2]
dcinfo = fileinfo("downloads/"+dlc)
dlcsize = File.size("downloads/"+dlc)
And lastly you can include the validation point:
if dlcsize > 0
puts "File found and is #{dlcsize} bytes."
logfile = open("test_results.csv", "a")
begin
logRow = "#{__FILE__}"
logfile.puts logRow + "," + "Passed".to_s
end
else
puts "Test Failed! File not found either is zero."
logfile = open("test_results.csv", "a")
begin
logRow = "#{__FILE__}"
logfile.puts logRow + "," + "Passed".to_s
end
end
回答6:
The way i handle this, is the following
Firefox download files end with .part
have all files' names being downloaded in a list after appending ".part" to them keep on looping on that list and check if any of those files still exist in the lsdir of the download folder
Python code:
import os
import time
def wait_till_download():
if len(new_part_files) > 0:
time.sleep(1)
for part_file in new_part_files:
if part_file in os.listdir("."):
print "Downloading..."
wait_till_download()
note: when there are no part files in os.listdir('.')
, that means downloading is finished