Webdriver: File Upload - c#

Is there a way to interact with a File Upload box in webdriver? The form field where the path gets put in is read only so I can't write to that.

You can do this without injecting JavaScript. You just need to get hold of the form field and type into it. Something like (using the Ruby API):
driver.find_element(:id, 'upload').send_keys('/foo/bar')

You can set the value of your input field using JavaScript. Considering that the id of the field is fileName the following example will set the value of the input to the file C:\temp\file.txt:
String script = "document.getElementById('fileName').value='" + "C:\\\\temp\\\\file.txt" + "';";
((IJavaScriptExecutor)driver).ExecuteScript(script);
In this example, driver is your WebDriver instance.
Please note that you have to use four backslashes (\) for Windows-like paths because you are required to pass double back-slashes to the JavaScript so you have to escape both with two additional slashes. The other option is to use a forward slash (e.g. "C:/tmp/file.txt") and that should also work.

For C#, SendKeys() works but you have to use \ in your file path instead of /
For example, the follow works :
string filePath = #"drive:\path\filename.filextension";
driver.FindElement(By.Id("fileInput")).SendKeys(filePath);
But the following doesn't work :
string filePath = "drive:/path/filename.filextension";
driver.FindElement(By.Id("fileInput")).SendKeys(filePath);

The problem I found is the upload dialog hangs the webdriver until closed.
That is, the element.click which invokes the upload dialog does not return until that upload dialog is closed. To be clear, upload dialog means an OS-native file selection.
Here is my solution (it's a bit complicated but *shrug* most workarounds for selenium webdriver problems must get complicated).
# presumes webdriver has loaded the web page of interest
element_input = webdriver.find_element_by_css_selector('input[id="uploadfile"]')
handle_dialog(element_input, "foobar.txt")
def handle_dialog(element_initiating_dialog, dialog_text_input):
def _handle_dialog(_element_initiating_dialog):
_element_initiating_dialog.click() # thread hangs here until upload dialog closes
t = threading.Thread(target=_handle_dialog, args=[element_initiating_dialog] )
t.start()
time.sleep(1) # poor thread synchronization, but good enough
upload_dialog = webdriver.switch_to_active_element()
upload_dialog.send_keys(dialog_text_input)
upload_dialog.send_keys(selenium.webdriver.common.keys.Keys.ENTER) # the ENTER key closes the upload dialog, other thread exits
Using python 2.7, webdriver 2.25.0, on Ubuntu 12, with firefox.

I am in search of 3rd party libraries too,
Unless there is no any other Window Then this works for me :
in C# add reference for System.Windows.Forms
using System.Windows.Forms;
string url = "http://nervgh.github.io/pages/angular-file-upload/examples/image-preview/";
string path = #"C:\Users\File_Path";
IWebDriver d = new ChromeDriver();
d.Navigate().GoToUrl(url);
d.FindElement(By.XPath("//input[#type='file']")).Click();
hread.Sleep(5000);
System.Windows.Forms.SendKeys.SendWait(path);
System.Windows.Forms.SendKeys.SendWait(#"{Enter}");

in my case i can upload file like solution that write hear but dialog window stuck the process, the driver cant reference to close this window, so i kill him manually:
foreach (var p in Process.GetProcessesByName("chrome"))
if (p.MainWindowTitle.ToLower().Contains("open"))
p.Kill();

We can use following (ruby API)
#driver.find_element(:xpath, "html/body/div[1]/div[2]/div[1]/form/div[4]/div[7]/table/tbody/tr[1]/td[2]/input").send_keys "C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg"
This is helped me to upload image.

Related

How can I sendKeys to the Windows Explorer with Selenium

A link on the page opens the file explorer of Windows.
Now I would like to send c:\temp\file1.txt to it.
Picture of Windows Explorer:
How can I do that?
What I tried is:
string BaseWindow = _webDriver.CurrentWindowHandle;
IJavaScriptExecutor jsExec = (IJavaScriptExecutor)_webDriver;
Thread.Sleep(1000);
jsExec.ExecuteScript("arguments[0].value = 'C:\\temp\\file1.txt'; ", BaseWindow);
which did not break the script actually but it didn't give the proper effect either.
Finally!! got it to work:
for all those people struggeling with the same thing... here is the solution:
you've got to switch to the active element then use sendkeys.
I got this:
System.Diagnostics.Process.Start("explorer.exe", "C:\\test.csv\"");
However that literally opens the Excel file. (which is also nice to know how to do that in automation by the way)
But I need to select a file in the Explorer (see 'pic of Windows Explorer')
I also tried this:
System.Diagnostics.Process.Start("explorer.exe /select", "C:\test.csv"");
Discovering this brought better results still not mission accomplished.
var FilePath = "'C:\\test.csv\'";
System.Diagnostics.Process.Start("Explorer.exe", #"/select,""" + FilePath + "\"");

Selenium File upload from URL instead of local file

Trying to upload a file with a HTML input element via Selenium/ChromeDriver.
If the file is a local file everything is OK.
But I need to upload from a URL. In that case the driver throws an error.
If I upload the URL with chrome manually (click on "Select file" and paste the URL as filename and click OK) the upload works as expected.
HTML:
<input type="file" name="file1">
C# code:
var driver = new ChromeDriver();
driver.Navigate().GoToUrl("<URL HERE>");
var input = driver.FindElement(By.Name(name));
ele.SendKeys("C:\\pic.png"); //works because local file exists
ele.SendKeys("https://wikipedia.org/static/favicon/wikipedia.ico"); //fails
Exception:
OpenQA.Selenium.WebDriverException: "invalid argument: File not found : https://wikipedia.org/static/favicon/wikipedia.ico
(Session info: chrome=92.0.4515.131)"
I found out that the exception is thrown because the drivers DefaultFileDetector cant resolve it to a file.
So I tried to implement my own FileDetector and assign it to the driver:
var allowsDetection = driver as IAllowsFileDetection;
if (allowsDetection != null)
{
allowsDetection.FileDetector = new DummyFileDetector();
}
DummyFileDetector:
class DummyFileDetector : IFileDetector
{
public bool IsFile(string keySequence)
{
return true;
}
}
But DummyFileDetector.IsFile is never called (it seems that allowsDetection.FileDetector = new DummyFileDetector() does not change the FileDetector of the driver).
I don't want to download the file and then upload it (if that is possible). As said manually set the URL in the file selection dialog does the trick, but not with Selenium.
Any ideas?
I searched many questions here and on other internet resources, and found that the only way to upload a file from external URL with driver.SendKeys() method is first to download it to your local disk and then upload with driver.SendKeys()
Proof
I've never used C# before, but I think a really simple way to go around this is downloading the file, reuploading it, then deleting it. I'm sure you can do it in C#. I understand in selenium python it is pretty simple to do that, I don't think python code would be helpful here though (lol)

Libragnar(Libtorrent Wrapper) LocalTorrent File, Instead of URL? C#/C++

Question:
Does anyone know how to add a torrent to LibRagnar using a filepath to a torrent, instead of a Url? (LibRagnar is a libtorrent Wrapper)
libragnar = C#
libtorrent = C++
Alternatively if anyone knows How I can use Libtorrent To add the torrent to a session, But use a local file (Whilst still controlling Everything else using Libragnar).But I am not sure where to start with Libtorrent.
Reason For Problem:
I have to use a filepath because the Torrent Requires cookie login to access it. So I either Need to get Libragnar to use a CookieCollection when getting a torrent from a URL or make it use a local ".torrent" file.
Problem:
I am currently trying to use a filepath instead of URL and the Torrent Status gives an error:unsupported URL protocol: D:\Programming\bin\Debug\Tempfiles\File.torrent. Which wont allow me to start it.
Example:
var addParams = new AddTorrentParams
{
SavePath = "C:\\Downloads",
Url = "D:\\Programming\\bin\\Debug\\Tempfiles\\File.torrent"
};
Edit: Answer from Tom W (Posted in C# Chatroom)
var ati = new AddTorrentParams()
{
TorrentInfo = new TorrentInfo("C:\thing.torrent"),
SavePath = #"C:\save\"
};
Note About Answer: I attempted to edit Tom W's post and add the answer he gave me in the Chatroom, However I guess it got declined? But Since he was the one who helped me I wanted him to get credit, and also wanted anyone else having this issue, to have an answer. So I had to add the answer to the bottom of my question.
From the libtorrent documentation it appears that:
The only mandatory parameters are save_path which is the directory
where you want the files to be saved. You also need to specify either
the ti (the torrent file), the info_hash (the info hash of the
torrent) or the url (the URL to where to download the .torrent file
from)
Libragnar's AddTorrentParams appears to be a wrapper around add_torrent_params and has a property called TorrentInfo. I suspect if you avoid setting the URL, and set this property to an instance of TorrentInfo instead, you ought to get the result you want.
Disclaimer: I've never worked with torrents before, don't know this library, and don't work in C++.

Manipulating "filename" of file dialog opened using a "print to pdf" option

I have over a thousand e-mails that need to be converted to individual PDFs. The code I've written is able to process the faux-print job up to the "Save PDF As..." Dialog Box.
I need to manipulate the filename in that dialog to the original filename. I cannot find a way to post a string to the filename section of the dialogbox, since this is an unconventional method posting on a separate process.
How do I send this information to an active dialog window that is unrelated to the process the application is calling?
public static void Main(string[] args)
{
string folderIn = Path.GetDirectoryName(#"Z:\Files up to 3-6-13\");
string folderOut = Path.GetDirectoryName(#"c:\users\athomas\desktop\Output");
string[] fileList = Directory.GetFiles(folderIn);
foreach(var fileName in fileList)
{
Console.WriteLine(fileName);
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo(fileName);
info.Verb = "Print";
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(info);
// This is where I need to say something like
// SaveDialog.SaveAs(fileName.SafeFileName)
if(p.HasExited == false)
{
p.WaitForExit(1000);
}
}
Console.ReadLine();
}
You are asking basically about hacking around, which means there is no safe way to do that. The possible way may look like this:
1) You enumerate windowses shown on the screen, via EnumWindows
2) You use for every window GetWindowText to find a Title of the Dialog you are searching for.
3) Ocassionaly there may be more then one dialog, Murphy's law is always there, so may be even with the same title. You can reduce collision risk by
3.a Call GetWindowLong with HWND of "dialog" you found
3.b Call GetParent to get HWND of parent window, that you already know
If you can avoid or may not care about case of window style&title collision, just jump over point (3)
4) Once you found your dialog, run over its HWND EnumChildWindows to get all controls of it
5) Find the contrlol you interested in via some attribute (usually Class_ID)
6) Execute SetWindowtext to set the text you like.
As I said before, there are several places were this process can fail.
For example:
You may happen to have multiple dialogs on the screen in the same moment
You may download a new version of PDF processor, and in SaveAs dialog may have something changed, so your code will break.
But considering that you are hacking, you may assume your own risks.
An excellent tool, may be the best tool, for window investigation on Windows, is probably Spy ++, which is available within visual studio installation. Using it you can try to find some unique attributes of a textbox of that dialog where you want to put the text in. Having that in your hands you can reliably query dialog's children collection to find the textbox.
After you mentioned .msg, I did a Google Search on the .msg file format and I was surprised to find it was well documented. It is an OLESS file, and there are APIs for loading those. I even found a CodeProject C# sample that was able to load an email I just saved from Outlook 2013!
It will be a bit of work since you will have to write code to "render" message how you see fit. Ex: It gives you the body, the recipients, and the attachments. You would have to decide what to do with the attachments and code that up. Then find a PDF library. But at least it is a programmatic solution, rather than relying on hacking the UI.
Also: A Google search for .MSG to PDF returned loads of tools to do this. One is a forum post referring to an Adobe Product called "Acrobat PDFMaker" so maybe you don't even need to write code.
Sorry to post 2 answers. I have a solution to the exact problem of prompting for the file. These instructions vary slightly based on the version of Windows, but you will get the idea:
Add a new printer that uses PDF printer driver
When it asks for the "port" click "Add Port" then "Local Port"
Enter in a file name. Ex: "C:\Users\Myself\MyPdf.pdf"
Complete the printing wizard as usual.
I tested this with the XPS printer and it worked
When you print to this printer, it writes to that exact file: No prompting! You will have to monitor the file (I suggest FileSystemWatcher) or poll for when the file is closed or something like that. After that, you can move the file elsewhere.

Is it possible to save data in another process with a C# app?

I have the following code:
p.StartInfo.FileName = "notepad.exe";
p.StartInfo.Arguments = "somefile.txt";
p.Start();
When "somefile.txt" is opened in notepad, its text will be modified. I want to save the new text in a temp file with the C# app automatically.
Is it possible to access this text and save it with C#?
It is sorta possible, you could use P/Invoke to call the SendMessage() method and generate the WM_COMMAND messages for the Edit + Select-All and Edit + Copy menu commands. That puts all text on the clip board, readily accessible to your program. You'll need to use the Spy++ utility to find out what the command identifiers are. Looks like 25 and 769 when I look at it on Win7.
There's a more direct way to discover the commands. In Visual Studio choose File + Open + File and select c:\windows\notepad.exe. Open the Menu node and double-click the "1" resource. That opens the menu editor, select Edit + Select-All and look at the Properties window for the ID.
Of course, this technique is specific to Notepad. The command IDs will be different for another program. As will be the code you need to find the proper window handle. Using Process.MainWindowHandle is treacherous at best, you don't know what specific instance of the process you need to select.
It would be very difficult to look at the text in-memory in the notepad process. It could be done, but it depends on the internal memory layout of notepad and your process may need administrative privileges depending on how the memory pages are protected.
Why not use a FileSystemWatcher to detect when the file has been modified, and then read the file in directly using c#?
http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx
Copy the somefile.txt before you start notepad to a temporary file/folder. Start notepad using this temporary file. And wait for Notepad to exit.
Then you can examine if the file is changed (checksum?).
Probably delete the file after the processing, or your system will be full with temp files.
You can bring notepad window to front and send CTRL+S. You will need to use pinvoke for that.
I really don't understand why you would want to use notepad?
If you need a user to edit a text file, and then your app take some action on the text itself, why not just give the user the ability to edit the text right in your app?
What does notepad give you that the TextBox control doesn't have?
Try something like this
using System.Windows.Forms;
using System.IO;
TextBox myEditor = new TextBox();
myEditor.Multiline = true;
myEditor.ScrollBars = ScrollBars.Vertical;
myEditor.AcceptsReturn = true;
myEditor.AcceptsTab = true;
myEditor.WordWrap = true;
// Get the text from the file.
StreamReader sr = new StreamReader("SomeFile.txt"))
myEditor.Text = sr.ReadToEnd();

Categories

Resources