Auto Download files in watir - selenium-webdriver

How to auto download the excel files from the browser in one click on the link, without going through the "save as" and other windows in watir. I am trying to keep it OS independent, so would not be interested in using win32ole gem.

for this task I tweaking my profile preferences
my code looks like this:
chrome driver:
profile = Selenium::WebDriver::Chrome::Profile.new
profile['download.default_directory'] = download_directory
profile['download.prompt_for_download'] = false
browser = Watir::Browser.new :chrome, :profile => profile
chrome driver 2:
prefs = {
'download' => {
'default_directory' => download_directory,
'prompt_for_download' => false,
'directory_upgrade' => true,
'extensions_to_open' => '',
},
'profile' => {
'default_content_settings' => {'multiple-automatic-downloads' => 1}, #for chrome version olde ~42
'default_content_setting_values' => {'automatic_downloads' => 1}, #for chrome newer 46
'password_manager_enabled' => false,
'gaia_info_picture_url' => true,
}
}
caps = Selenium::WebDriver::Remote::Capabilities.chrome
caps['chromeOptions'] = {'prefs' => prefs}
browser = Watir::Browser.new :chrome, :desired_capabilities => caps
firefox:
profile = Selenium::WebDriver::Firefox::Profile.new
profile['browser.download.lastDir'] = download_directory
profile['browser.download.folderList'] = 2
profile['browser.download.dir'] = download_directory
profile['browser.download.manager.showWhenStarting'] = false
profile['browser.helperApps.alwaysAsk.force'] = false
profile['browser.helperApps.neverAsk.openFile'] = "text/csv,application/pdf"
profile['browser.helperApps.neverAsk.saveToDisk'] = "text/csv,application/pdf"
profile['pdfjs.disabled'] = true
browser = Watir::Browser.new :firefox, :profile => profile
(firefox example for me working only for pdf files)
but selenium browsers download has many bugs
some problem in chrome or firefox webdriver (like this http://code.google.com/p/chromedriver/issues/detail?id=130)
do not allow write good tests for file downloads
I wrote the following ruby script for download files
require ‘rubygems’
require “net/http”
require “uri”
def download(_url, _download_path = ”)
url = URI.parse _url
http_object = Net::HTTP.new(url.host, url.port)
http_object.use_ssl = true if (url.scheme == ‘https’ || url.port == 443)
http_object.start.request_get(url.path) do |response|
start_time = Time.now
response["Content-Disposition"] =~ /^.+?filename=”(.+?)”$/
file_name = $1
file = open(_download_path + file_name, ‘wb’)
length = response['Content-Length'].to_i
response.read_body do |fragment|
file.write(fragment)
end
file.close
file_size = File.size(_download_path + file_name)/1024.0/1024.0
puts “-“*80
puts “Download time – #{Time.now – start_time}”
puts “Download speed – #{file_size/(Time.now – start_time)} MB/s”
puts “-“*80
end
end
download(‘http://storagemadeeasy.com/files/1cf064a30aba6d1b8fbc0fba8ac8be5b.jpg’)
I hope this code will be useful for those who need test file download (not browser file download dialog window)

It appears to be unique to each browser. Alister Scott wrote this << try that.

Related

How to Auto Login using VBS script

I'm just new to this. I am currently working for a project here in our office and I already have the script on how to open multi-tab IE in one window. Here is the script that I use for it.
Const navOpenInBackgroundTab = &H1000
site1 = "http://site1.com/"
site2 = "https://site2.com"
Set oIE = CreateObject("InternetExplorer.Application")
oIE.Visible = True
oIE.Navigate2 site1
oIE.Navigate2 site2,navOpenInBackgroundTab
Set oIE = Nothing
But two of these websites needs log in information. I want to know the script that will allow me to auto log in to these websites. I was wondering what I need to add on the script above so that it will auto-log in every time I use the script.
Here is one of the website:
https://myapps.uhc.com/Citrix/AccessPlatform/auth/login.aspx
I hope someone can help me figure it out, thanks
Long story short, you'd have an easier time using Firefox + Greasemonkey or Chrome + Tampermonkey.
Enumerating background tabs requires the use of Shell.Application object .Windows() method. The ambiguous window object seems to break DOMelement.parentNode and similar, so that each time you navigate the DOM you have to re-establish the complete hierarchy starting with tabCollection.item(i).document. Is the username field named user, username, login name, login ID, email, or something else? You can try to predict it with a regex, but there'll probably be some trial and error involved if you plan to extend this script for logging into other sites.
The impossible part, though, is form submission. Does the form submission call a postback to set hidden input values prior to post? If so, then form.submit() might not fire the necessary events before submission, resulting in an auth failure. This was the case for two sites I tested.
If you could fire the click() event of the submit button, that might help. But is the submit button a button? An input type=button? An image? A stylized hyperlink? A div? OK, so maybe sending Enter in the password field would be better. I've been experimenting with initKeyboardEvent and passwordField.dispatchEvent(evt) for a couple of hours now, and it seems that here again, the ambiguous window object resulting from Shell.Application is preventing success.
Here's my almost-working solution. It's a batch + Jscript hybrid. Save it with a .bat extension, and do with it what you will. *shrug* Maybe form.submit() will work for the sites you are using?
#if (#CodeSection == #Batch) #then
#echo off & setlocal
cscript /nologo /e:JScript "%~f0"
goto :EOf
#end // end Batch / begin JScript hybrid code
var navOpenInBackgroundTab = 4096,
site = [
"http://www.site1.com/",
"http://www.site2.com/"
],
IE = WSH.CreateObject("InternetExplorer.Application"),
oSH = WSH.CreateObject("Shell.Application"),
username = 'username',
password = 'password';
IE.Visible = true;
for (var i=0; i<site.length; i++) {
IE.Navigate(site[i], i ? 4096 : null);
}
var tabs = oSH.Windows();
for (var x = 0; x < tabs.Count; x++) {
if (!!(tabs.item(x))) {
WSH.Echo('tab ' + x);
var entered = { 'username': 0, 'password': 0 };
while (tabs.item(x).Busy || tabs.item(x).ReadyState != 4) WSH.Sleep(50);
// sleep 1 second regardless, just in case there's some jquery crap going on
WSH.Sleep(1000);
for (var i in tabs.item(x).document.forms) {
if (i == 'length') break;
var inputs = tabs.item(x).document.forms[i].getElementsByTagName('input');
for (var j = inputs.length; j--;) {
if (/\b(login|user(name|id)?|e\-?mail)\b/i.test(inputs[j].name)
&& inputs[j].type.toLowerCase() == "text") {
entered.username = inputs[j];
inputs[j].value = username;
} else if (inputs[j].type.toLowerCase() == 'password') {
entered.password = inputs[j];
inputs[j].value = password;
}
}
if (entered.username && entered.password) {
tabs.item(x).document.forms[i].submit();
/* === NOT QUITE WORKING ===
try {
var evt = tabs.item(x).document.createEvent('KeyboardEvent');
// What is "window"? tabs.item(x) doesn't work, nor does IE.
evt.initKeyboardEvent('keypress', true, true, tabs.item(x),
false, false, false, false, 13, 13);
entered.password.dispatchEvent(evt);
}
catch(e) { WSH.Echo(e.message) }
*/
i = tabs.item(x).document.forms.length;
}
}
}
}
var IE = null;
Another idea would be to do passwordElement.focus() and use WshShell.SendKeys() to send Enter, but then you wouldn't be able to load the tabs in the background. I haven't found a way to activate tabs programmatically yet; but if they're loaded in the foreground, they're already active. Although this doesn't load tabs in the background, it works better than the first method.
#if (#CodeSection == #Batch) #then
#echo off & setlocal
cscript /nologo /e:JScript "%~f0"
goto :EOf
#end // end Batch / begin JScript hybrid code
var sites = {
"http://www.site1.com/" : {
'username': 'site1user',
'password': 'site1pass'
},
"http://www.site2.net/" : {
'username': 'site2user',
'password': 'site2pass'
}
},
IE = WSH.CreateObject("InternetExplorer.Application"),
oSH = WSH.CreateObject("Shell.Application"),
WshShell = WSH.CreateObject("WScript.Shell"),
proc = GetObject("winmgmts:").ExecQuery("SELECT Handle FROM Win32_Process "
+ "WHERE Name='iexplore.exe'"),
handle = new Enumerator(proc).item().Handle;
awesomeness:
for (var url in sites) {
// if not a new window, open a new tab
IE.Navigate(url, IE.Visible ? 2048 : null);
IE.Visible = true;
// give the tab a chance to load
WSH.Sleep(1000);
var tabs = oSH.Windows(),
tab = tabs.item(tabs.Count - 1),
entered = { 'username': 0, 'password': 0 };
while (tab.Busy || tab.ReadyState != 4) WSH.Sleep(50);
for (var i in tab.document.forms) {
if (i == 'length') break;
var inputs = tab.document.forms[i].getElementsByTagName('input');
for (var j = inputs.length; j--;) {
if (/\b(login|user(name|id)?|e\-?mail)\b/i.test(inputs[j].name)
&& inputs[j].type.toLowerCase() == "text") {
entered.username = inputs[j].value = sites[url].username;
} else if (inputs[j].type.toLowerCase() == 'password') {
entered.password = inputs[j];
inputs[j].value = sites[url].password;
}
if (entered.username && entered.password) {
// force IE window to have focus
while (!(WshShell.AppActivate(handle))) WSH.Sleep(50);
entered.password.focus();
WshShell.SendKeys('{END}{ENTER}');
continue awesomeness;
}
}
}
}
var IE = null;

"error: expected a type" error when running "pod spec lint"

I'm attempting to convert an existing project into a cocoapod so that it will be easier to use however when I run
pod spec lint --verbose
I get a number of errors similar to
- ERROR | [iOS] xcodebuild: CoreDataServices/CoreDataServices/Services/Count/CDSCountService.m:28:9: error: use of undeclared identifier 'NSFetchRequest'
I have the following as my podspec:
Pod::Spec.new do |s|
s.name = "CoreDataServices"
s.version = "0.2.0"
s.summary = "CoreDataServices contains a set of helper classes to abstract away common core data functionality."
s.homepage = "http://www.williamboles.me"
s.license = { :type => 'MIT',
:file => 'LICENSE.md' }
s.author = "William Boles"
s.platform = :ios, "8.0"
s.source = { :git => "https://github.com/wibosco/CoreDataServices.git",
:branch => "master",
:tag => s.version }
s.source_files = "CoreDataServices/**/*.{h,m}"
s.public_header_files = "CoreDataServices/**/*.{h}"
s.frameworks = 'UIKit', 'CoreData'
s.requires_arc = true
end
I have cocoapod version 0.39.0 installed.
Building the project using xcodebuild outside of cocoapods results in the project being built without errors.
I managed to get there in the end but it's an odd one:
Pod::Spec.new do |s|
s.name = "CoreDataServices"
s.version = "0.2.0"
s.summary = "CoreDataServices contains a set of helper classes to abstract away common core data functionality."
s.homepage = "http://www.williamboles.me"
s.license = { :type => 'MIT',
:file => 'LICENSE.md' }
s.author = "William Boles"
s.platform = :ios, "8.0"
s.source = { :git => "https://github.com/wibosco/CoreDataServices.git",
:branch => "master",
:tag => s.version }
s.source_files = "CoreDataServices/**/*.{h,m}"
s.public_header_files = "CoreDataServices/**/*.{h}"
s.requires_arc = true
s.frameworks = 'UIKit', 'CoreData'
end
I moved s.requires_arc = true to be above s.framework = 'UIKit', 'CoreData' and the errors went away.
I also noticed that if I inverted the ordering of the framesworks so that it becomes
s.frameworks = 'CoreData', 'UIKit'
s.requires_arc = true
that also worked

How to get MIME type of a file in PHP 5.5?

I am using mime_content_type() in PHP 5.5 to get a MIME type, but it throws fatal: error function not found.
How can I achieve this on PHP 5.5?
Make use of the finfo() functions.
A simple illustration:
<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo, "path/to/image_dir/image.gif");
finfo_close($finfo);
OUTPUT :
image/gif
Note : Windows users must include the bundled php_fileinfo.dll DLL file in php.ini to enable this extension.
I've spent too much time trying to get the finfo functions to work, properly. I finally just ended up creating my own function to match the file extension to any array of mime types. It's not a full-proof way of assuring that the files are truly what the extension denotes them to be, but that problem can be mitigated by how you process I/O of said files on your server(s).
function mime_type($file) {
// there's a bug that doesn't properly detect
// the mime type of css files
// https://bugs.php.net/bug.php?id=53035
// so the following is used, instead
// src: http://www.freeformatter.com/mime-types-list.html#mime-types-list
$mime_type = array(
"3dml" => "text/vnd.in3d.3dml",
"3g2" => "video/3gpp2",
"3gp" => "video/3gpp",
"7z" => "application/x-7z-compressed",
"aab" => "application/x-authorware-bin",
"aac" => "audio/x-aac",
"aam" => "application/x-authorware-map",
"aas" => "application/x-authorware-seg",
"abw" => "application/x-abiword",
"ac" => "application/pkix-attr-cert",
"acc" => "application/vnd.americandynamics.acc",
"ace" => "application/x-ace-compressed",
"acu" => "application/vnd.acucobol",
"adp" => "audio/adpcm",
"aep" => "application/vnd.audiograph",
"afp" => "application/vnd.ibm.modcap",
"ahead" => "application/vnd.ahead.space",
"ai" => "application/postscript",
"aif" => "audio/x-aiff",
"air" => "application/vnd.adobe.air-application-installer-package+zip",
"ait" => "application/vnd.dvb.ait",
"ami" => "application/vnd.amiga.ami",
"apk" => "application/vnd.android.package-archive",
"application" => "application/x-ms-application",
// etc...
// truncated due to Stack Overflow's character limit in posts
);
$extension = \strtolower(\pathinfo($file, \PATHINFO_EXTENSION));
if (isset($mime_type[$extension])) {
return $mime_type[$extension];
} else {
throw new \Exception("Unknown file type");
}
}
Edit:
I'd like to address Davuz's comment (since it keeps getting up-voted) and remind everyone that I put in the pseudo disclaimer at the top that this isn't "full-proof." So, please keep that in mind when considering the approach I've offered in my answer.
mime_content_type() is not deprecated and works fine.
Why is mime_content_type() deprecated in PHP?
http://php.net/manual/en/function.mime-content-type.php
As of PHP 5.3, it's even built-in.
$finfo = finfo_open(FILEINFO_MIME_TYPE); should do it.
Taken from the php.net docs. Your function is deprecated and probably already removed.
http://www.php.net/manual/en/function.finfo-file.php
You should understand that file_get_contents will upload whole file to the memory, it is not good way to get only mime type. You don't need to use buffer method and file_get_contents function in this case.
To prevent any errors and warnings, better do like this.
$filename = 'path to your file';
if (class_exists('finfo')) {
$finfo = new finfo(FILEINFO_MIME_TYPE);
if (is_object($finfo)) {
echo $finfo->file($filename);
}
} else {
echo 'fileinfo did not installed';
}
Also you should know $finfo->file will throw PHP Warning if it fail.
If fileinfo is not installed properly, and you have a fresh version of PHP, you can get mime type from headers.
You can use cURL to get mime type from headers.
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_HEADER => true,
CURLOPT_NOBODY => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 1,
CURLOPT_URL => $link)
);
$headers = curl_exec($ch);
curl_close($ch);
if (preg_match('/Content-Type:\s(.*)/i', $headers, $matches)) {
echo trim($matches[1], "\t\n\r");
}else {
echo 'There is no content type in the headers!';
}
Also you can use get_headers function, but it more slow than cURL request.
$url = 'http://www.example.com';
$headers = get_headers($url, 1);
echo $headers['Content-Type'];
Get the image size using:
$infFil=getimagesize($the_file_name);
and
echo $infFil["mime"]
The getimagesize returns an associative array which have a MIME key and obviously the image size too
I used it and it works
I use the MimeTypeTool from Bat (https://github.com/lingtalfi/Bat)
It uses fileinfo if available, and defaults back to an "extension => mime type" mapping otherwise.
This is the best solution I found by combining two very good posts
// Thanks to http://php.net/manual/en/function.mime-content-type.php#87856
function getMimeContentType($filename, $ext)
{
if(!function_exists('mime_content_type'))
{
if($mime_types = getMimeTypes())
{
if (array_key_exists($ext, $mime_types))
{
return $mime_types[$ext];
}
elseif (function_exists('finfo_open'))
{
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);
return $mimetype;
}
}
return 'application/octet-stream';
}
return mime_content_type($filename);
}
// Thanks to http://php.net/manual/en/function.mime-content-type.php#107798
function getMimeTypes()
{
$url = 'http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types';
$mimes = array();
foreach(#explode("\n",#file_get_contents($url)) as $x)
{
if(isset($x[0]) && $x[0]!=='#' && preg_match_all('#([^\s]+)#', $x, $out) && isset($out[1]) && ($c = count($out[1])) > 1)
{
for($i=1; $i < $c; $i++)
{
$mimes[$out[1][$i]] = $out[1][0];
}
}
}
return (#sort($mimes)) ? $mimes : false;
}
Use it link this:
$filename = '/path/to/the/file.pdf';
$ext = strtolower(array_pop(explode('.',$filename)));
$content_type = getMimeContentType($filename, $ext);
Will continue to work even if the mime_content_type function is no longer supported in php.

Zend Download File Chrome

When I use the code below to download a file it works fine in IE, Firefox, but with Chrome you can see that the layout and view is sent back to the browser in the console.The status is set to cancel and the entire line is highlighted in red. The file is downloaded OK.
After the exit; there are various header opions I have tried, but to no avail
if ($request->isPost()) {
$this->_helper->viewRenderer->setNoRender(true);
$this->_helper->layout()->disableLayout();
$file_fullpath = "C:/eclipse-php/workspace/Dartfire/uploads/data/logo.jpg";
$mtype = '';
// magic_mime module installed?
if (function_exists('mime_content_type')) {
$mtype = mime_content_type($file_fullpath);
}
// fileinfo module installed?
else if (function_exists('finfo_file')) {
$finfo = finfo_open(FILEINFO_MIME); // return mime type
$mtype = finfo_file($finfo, $file_fullpath);
finfo_close($finfo);
}
$size = filesize($file_fullpath);
header('Content-Type: image/jpg');
header('Content-Disposition: attachment; filename="logo.jpg"');
readfile($file_fullpath);
exit;
//header("Content-type: application/octet-stream");
/*
$this->getResponse()
->setHeader('Content-Description', 'File Transfer', true)
->setHeader('Content-Type', $mtype, true) // change to application/pdf
->setHeader('Content-Disposition', "attachment; filename={$document->getFilename()}", true)
->setHeader('Content-length', $size, true)
->setHeader('Content-Transfer-Encoding', 'binary', true)
->setHeader("Content-type", "application/octet-stream")
->setHeader('Cache-control', 'private')
->appendBody(readfile($file_fullpath));
//->sendHeaders();
//$this->getResponse()->sendResponse();
//Zend_Wildfire_Channel_HttpHeaders::getInstance()->flush();
}
You'd have to place any header() calls before any output is sent to the browser. So, in your case this would need to be done before the readline() call.

Scala Lift - Save uploaded files to server directory

I'm currently storing images within the webapp folder of my Lift project, which I know will cause problems in future.
val path = "src/main/webapp/files/"
And the code I'm using to save it:
case Full(file) =>
val holder = new File(path, "test.txt")
val output = new FileOutputStream(holder)
try {
output.write(file)
} finally {
output.close()
}
}
What I'm trying to do is save the to the server root in an easily manageable folder called files, so SERVER_ROOT/files outside of the project folder.
Firstly how would I access the path to the root of the server so I can save them there?
Secondly how would I serve these files from my app, so I can display them on a page?
Thanks in advance, any help much appreciated :)
You have to store file to exact place on filesystem according to absolute path. I have written this code and it works, so maybe it helps you:
def storeFile (file : FileParamHolder): Box[File] =
{
getBaseApplicationPath match
{
case Full(appBasePath) =>
{
var uploadDir = new File(appBasePath + "RELATIVE PATH TO YOUR UPLOAD DIR")
val uploadingFile = new File(uploadDir, file.fileName)
println("upload file to: " + uploadingFile.getAbsolutePath)
var output = new FileOutputStream(uploadingFile)
try
{
output.write(file.file)
}
catch
{
case e => println(e)
}
finally
{
output.close
output = null
}
Full(uploadingFile)
}
case _ => Empty
}
}
and this is my getBaseApplicationPath function which finds out absolute path of local machine (server or your devel PC):
def getBaseApplicationPath: Box[String] =
{
LiftRules.context match
{
case context: HTTPServletContext =>
{
var baseApp: String = context.ctx.getRealPath("/")
if(!baseApp.endsWith(File.separator))
baseApp = baseApp + File.separator
Full(baseApp)
}
case _ => Empty
}
}

Resources