如何通过使用 Selenium Grid 将文件从本地计算机传输到远程 Web 服务器来上传文件

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

使用 Selenium 网格上传文件:

代码

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");
    }
}

异常

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)

该文件存在于本地节点,但不存在于远程节点。如果文件在远程节点上,则效果很好。文件存在于本地节点,但不存在于远程节点:https://i.stack.imgur.com/f31Wb.png

我读了这个:

如何将文件传递到远程节点?

编辑

Firefox、IE 和 Edge Chromium 出现同样的错误

火狐:

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)

当我将文件复制到远程客户端时,它再次运行良好:(

调试: Debug with Firefox

这个错误信息...

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

...表示客户端计算机上不存在所需的文件。


本地文件检测器

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 可以在运行时自动将文件从本地机器传输到远程网络服务器。这允许从远程机器上传文件运行 进行测试。默认不开启,可通过如下方式开启:

  • 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
    
  • Java脚本:

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

    driver.fileDetector = LocalFileDetector()
    

这个用例

如果您 运行 在 上进行测试,那么您需要让您的远程驱动程序知道需要上传的文件位于本地机器上,而不是远程机器上。在这些情况下,要将文件从客户端计算机上传到远程服务器,WebDriver 可以在运行时自动将文件从本地计算机传输到远程 Web 服务器,您可以使用以下代码区块:

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

结尾

Selecting and uploading files while running your tests on Selenium Grid

感谢@DebanjanB 帮助我找到解决方案 - 我对你的回复投了赞成票,这是说明它确实有效的另一个答案。

我的问题:

在本地,我针对本地 运行 Selenium 服务器(运行 selenium-server-4.0.0-beta-4.jar 文件)进行了 运行 Selenium 测试,我使用的是 chromedriver.exe 文件也是。

我的测试(用 TypeScript 编写)使用以下方式上传文件:

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

运行 本地没有问题。但是在我们的 DevOps 管道中,运行 Docker 使用 selenium/standalone-chrome 图像,就像驱动程序找不到文件一样:

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

即使 运行 我们已经确认确实在正确的文件夹中找到了该文件:

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

意味着文件确实位于 /home/vsts/work/1/s/selenium/tests/flows/testfile.txt.

我和我的团队用谷歌搜索并搜索了为什么会这样,并找到了@DebanjanB 的答案。

我们没有意识到 selenium/standalone-chrome Docker 图像是 运行 Selenium Grid 服务器,它是“远程”而不是“本地”。因此,当 运行“远程”时,驱动程序找不到文件。

解决方法

我们添加了

driver.setFileDetector(new FileDetector());

之前

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

现在,当 运行 针对我们管道中的 docker 容器时,我们的测试也通过了!

来自 Selenium 的文档:

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.

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

我希望这能对遇到同样问题的人有所帮助:-)