How to upload a file by transfering the file from the local machine to the remote web server using Selenium Grid
Asked Answered
C

2

5

File Upload with a Selenium Grid:

Code

import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.LocalFileDetector;
import org.openqa.selenium.remote.RemoteWebDriver;

public class Main 
{
    
    public static void main(String[] args) throws MalformedURLException
    {
          DesiredCapabilities capabilities = DesiredCapabilities.internetExplorer();
          capabilities.setBrowserName("internet explorer");
    
          RemoteWebDriver driver = new RemoteWebDriver(new URL("http://URL:4444/wd/hub"), capabilities);
          driver.setFileDetector(new LocalFileDetector());
          driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
    
          driver.get("https://url.de/index.xhtml");
          driver.findElement(By.xpath("//*[@id='form:sdsupload']/span")).click();
        
          WebElement addFile = driver.findElement(By.xpath("//input[@type='file']"));
          ((RemoteWebElement) addFile ).setFileDetector(new LocalFileDetector());
          addFile.sendKeys("C:\\daten\\test\\test2.xml");
    }
}

Exception

Jun 26, 2020 3:47:43 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFORMATION: Detected dialect: W3C
Exception in thread "main" org.openqa.selenium.InvalidArgumentException: Attempting to upload file 'C:\daten\test\test2.xml' which does not exist.
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03'
System info: host: 'xxx', ip: 'xxx', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_171'
Driver info: org.openqa.selenium.remote.RemoteWebDriver
Capabilities {acceptInsecureCerts: false, browserName: internet explorer, browserVersion: 11, javascriptEnabled: true, pageLoadStrategy: normal, platform: WINDOWS, platformName: WINDOWS, proxy: Proxy(), se:ieOptions: {browserAttachTimeout: 0, elementScrollBehavior: 0, enablePersistentHover: true, ie.browserCommandLineSwitches: , ie.ensureCleanSession: false, ie.fileUploadDialogTimeout: 3000, ie.forceCreateProcessApi: false, ignoreProtectedModeSettings: false, ignoreZoomSetting: false, initialBrowserUrl: http://localhost:5494/, nativeEvents: true, requireWindowFocus: false}, setWindowRect: true, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, webdriver.remote.sessionid: ae053a22-c088-402e-8de1-f25...}
Session ID: ae053a22-c088-402e-8de1-f25c4398ccbf
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
    at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
    at org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:285)
    at org.openqa.selenium.remote.RemoteWebElement.sendKeys(RemoteWebElement.java:106)
    at de.xxx.xxx.keywords.Main.main(Main.java:41)

The file exists on the local node, but not on the remote node. If the file is on the remote node, it works great. The File exists on local node, but not on remote node: https://i.sstatic.net/f31Wb.png

I read this:

How can I pass a file to the remote node?

Edit

The same Error with Firefox, IE and Edge Chromium

Firefox:

Exception in thread "main" org.openqa.selenium.InvalidArgumentException: File not found: C:\daten\test\test3.xml
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03'
System info: host: 'xxx', ip: 'xxx', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_171'
Driver info: org.openqa.selenium.remote.RemoteWebDriver
Capabilities {acceptInsecureCerts: true, browserName: firefox, browserVersion: 60.5.0, javascriptEnabled: true, moz:accessibilityChecks: false, moz:geckodriverVersion: 0.25.0, moz:headless: false, moz:processID: 624, moz:profile: C:\Users\username\Ap..., moz:useNonSpecCompliantPointerOrigin: false, moz:webdriverClick: true, pageLoadStrategy: normal, platform: XP, platformName: XP, platformVersion: 10.0, rotatable: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, webdriver.remote.sessionid: 8801c61e-6d61-488b-8f86-c0a...}
Session ID: 8801c61e-6d61-488b-8f86-c0a1fb2f2df8
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
    at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
    at org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:285)
    at org.openqa.selenium.remote.RemoteWebElement.sendKeys(RemoteWebElement.java:106)
    at de.xxx.xxx.keywords.Main.main(Main.java:52)

When I copy the file to the remote client it works great again :(

Debug: Debug with Firefox

Crystlecs answered 26/6, 2020 at 13:10 Comment(0)
R
10

This error message...

Exception in thread "main" org.openqa.selenium.InvalidArgumentException: Attempting to upload file 'C:\daten\test2.xml' which does not exist.

...implies that the desired file doesn't exist on the client machine.


Local file detector

The Local File Detector allows the transfer of files from the client machine to the remote server. In case a test needs to upload a file to a web application, a remote WebDriver can automatically transfer the file from the local machine to the remote web server during runtime. This allows the file to be uploaded from the remote machine running the test. It is not enabled by default and can be enabled as follows:

  • Java:

    driver.setFileDetector(new LocalFileDetector());
    
  • Python:

    from selenium.webdriver.remote.file_detector import LocalFileDetector
    
    driver.file_detector = LocalFileDetector()
    
  • C#:

    var allowsDetection = this.driver as IAllowsFileDetection;
    if (allowsDetection != null)
    {
       allowsDetection.FileDetector = new LocalFileDetector();
    }
    
  • Ruby:

    @driver.file_detector = lambda do |args|
      # args => ["/path/to/file"]
      str = args.first.to_s
      str if File.exist?(str)
    end
    
  • JavaScript:

    var remote = require('selenium-webdriver/remote');
    driver.setFileDetector(new remote.FileDetector); 
    
  • Kotlin:

    driver.fileDetector = LocalFileDetector()
    

This usecase

If you are running your tests on Selenium Grid then you need to let your remote driver know that the file that needs to be uploaded is residing on the local machine and not on remote machine. In those cases, to upload a file from the client machine to the remote server, WebDriver can automatically transfer the file from the local machine to the remote web server during runtime you can use the following code block:

WebElement addFile = driver.findElement(By.xpath("//input[@type='file']"));
((RemoteWebElement)addFile).setFileDetector(new LocalFileDetector());
addFile.sendKeys("C:\\daten\\test2.xml");

Outro

Selecting and uploading files while running your tests on Selenium Grid

Rufena answered 26/6, 2020 at 13:40 Comment(5)
i post the new code with the same error message and a Screenshot that the file existsCrystlecs
@Crystlecs Can you try once with Chrome or Firefox please. There seems to besome issue with IE.Rufena
It WORKS :) THANKS! I don't know what's the Problem. It doesn't work with Firefox, Edge Chromium and IE. When I rewritten the sendKeys command, it worked. I don't know why.Crystlecs
hank you very much! I think the problem was a broken xml file.Crystlecs
I am getting failure intermittently though localFileDetector is set. #68008269Bellini
P
0

Thank you @DebanjanB for helping me finding the solution - I've upvoted your response, and this is another answer to state it indeed works.

My problem:

Locally, I was running Selenium tests against a locally running Selenium server (running selenium-server-4.0.0-beta-4.jar file), and I was using chromedriver.exe file too.

My tests (written in TypeScript) that uploaded files using:

await (
  await driver.findElement(By.xpath("//form//input[@id='upload-input']"))
).sendKeys(join(__dirname, "testfile.txt"));

Ran without problems locally. But in our DevOps pipeline, running Docker using the selenium/standalone-chrome image, it was like the driver couldn't find the file:

InvalidArgumentError: invalid argument: File not found: /home/vsts/work/1/s/selenium/tests/flows/testfile.txt

Even though we had confirmed that the file was indeed found in the correct folder by running:

> pwd
/home/vsts/work/1/s
> find . -name testfile.txt
./selenium/tests/flows/testfile.txt

Meaning the file was indeed located at /home/vsts/work/1/s/selenium/tests/flows/testfile.txt.

My team and I Googled and searched why this was and found @DebanjanB's answer.

What we didn't realize was that the selenium/standalone-chrome Docker image is running a Selenium Grid server, which is "remote" rather than "local". And so the driver can't find the file when running "remote".

The solution

We added

driver.setFileDetector(new FileDetector());

Before

await (
  await driver.findElement(By.xpath("//form//input[@id='upload-input']"))
).sendKeys(join(__dirname, "testfile.txt"));

And now our tests pass when running against the docker container in our pipeline too!

From Selenium's documentation:

The Local File Detector allows the transfer of files from the client machine to the remote server. For example, if a test needs to upload a file to a web application, a remote WebDriver can automatically transfer the file from the local machine to the remote web server during runtime. This allows the file to be uploaded from the remote machine running the test.

Source: https://www.selenium.dev/documentation/webdriver/remote_webdriver/#local-file-detector

I hope this will help someone struggling with the same problem :-)

Pedagogue answered 15/9, 2021 at 9:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.