【问题标题】:Selenium file_detector unable to find file to upload to selenium gridSelenium file_detector 找不到要上传到 selenium 网格的文件
【发布时间】:2019-01-30 00:33:04
【问题描述】:

使用 selenium webdriver 3.12 并在 saucelabs(硒网格)上运行文件上传测试作为 Win 10 chrome 66。我尝试实现文件检测器并将密钥发送到我的代码中,以便系统可以将文件从我的本地机器并在 saucelabs 中使用,但遇到错误:

Selenium::WebDriver::Error::ExpectedError:
       invalid argument: File not found : /Users/john.doe/Work/project/spec/support/apps/files/suggested_content/valid_sc.csv
         (Session info: chrome=66.0.3359.117)
         (Driver info: chromedriver=2.38.551601 (edb21f07fc70e9027c746edd3201443e011a61ed),platform=Windows NT 10.0.10586 x86_64)

我实现这一点的方式是将文件检测器添加为我的规范帮助程序的一部分,然后在我的规范文件顶部需要规范帮助程序,然后使用 sendkeys 发送文件上传的路径。类似于Saucelabs best practices here

来自我的规范助手内部的一个 sn-p... 我已经实例化了驱动程序并添加了文件检测器的代码(这是从酱汁和 ruby​​doc 的使用稍微调整的,因为它使用当前会话驱动程序而不是驱动程序) :

       Capybara::Selenium::Driver.new(app,
                                       browser: :remote,
                                       url: url,
                                       desired_capabilities: capabilities)
        end

Capybara.current_session.driver.browser.file_detector = lambda do |args|
            str = args.first.to_s
            str if File.exist?(str)
          end

以及上传文件的调用方法:

    def add_file(file_name = 'valid_sc.csv')
      path = './spec/support/apps/files/suggested_content/'
      expose_file_upload
      page.find('input[id*=content--add-file')
          .send_keys(File.expand_path(path + file_name))
    end

该文件肯定位于该路径,并且当我在本地运行测试时工作正常。我在这里错过了什么?

【问题讨论】:

    标签: ruby selenium rspec capybara selenium-grid


    【解决方案1】:

    这为我解决了问题。在注册远程驱动程序后,我将这个 sn-p 的底部添加到我的spec_helper.rb

    Capybara.register_driver :selenium do |app|
      # ...
    
      Capybara::Selenium::Driver.new(app,
                                     browser: :remote,
                                     url: url,
                                     desired_capabilities: capabilities)
    end
    
    # Add file upload capability on remote driver
    page.driver.browser.file_detector = lambda do |args|
      str = args.first.to_s
      str if File.exist?(str)
    end
    

    确保仅在使用远程驱动程序时执行此操作,否则常规的本地 selenium 驱动程序将不知道如何处理 file_detector 方法。

    【讨论】:

    • 这就是为什么你应该把它放在用于远程驱动程序的驱动程序注册中,如我的回答所示 - 然后它只会与远程驱动程序一起使用。
    【解决方案2】:

    在 saucelabs 上使用 capybara 测试文件上传有点棘手。 前段时间我也遇到过类似的问题。

    尝试不使用文件检测器并使用 capybara 的 attach_file 方法。

    概览:

    如果您使用的是 attach_file capybara 函数,则在运行文件上传时,这将验证您本地机器上的文件存在路径,请参见下面来自 ruby​​docs 的 attach_file 方法源代码

        def attach_file(locator = nil, path, make_visible: nil, **options)
          Array(path).each do |p|
            raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
          end
          # Allow user to update the CSS style of the file input since they are so often hidden on a page
          if make_visible
            ff = find(:file_field, locator, options.merge(visible: :all))
            while_visible(ff, make_visible) { |el| el.set(path) }
          else
            find(:file_field, locator, options).set(path)
          end
        end
    

    但在执行时,它会在 saucelabs 机器上搜索相同的路径,如果文件不存在于 saucelabs 机器上,则会出错。

    所以对于简单的解决方案,您可以创建一个自定义 attach_file 方法,无需路径验证,如下所示:

        def attach_file_new(locator, path, options={})
          find(:file_field, locator, options).set(path)
        end
    

    您可以通过执行javascript或jquery方法检查和设置元素的可见性,并提供该方法的实际saucelabs机器的文件路径。

    所以它不会验证您本地机器上的路径,而是直接从 saucelabs 机器中选择文件。

    更多信息: 在 saucelabs 上执行测试时,它会在执行时创建机器,因此您之前无法将文件放在该机器上。

    所以更好的方法是在实际文件上传步骤之前添加一些设置步骤,在这些步骤中,您打开浏览器并点击直接下载文件 url,例如一些 Dropbox 文件 url 或谷歌驱动器直接文件下载 url,它将为您下载文件在 saucelabs 机器上,下载将始终在下载目录中,因此您可以将该目录的路径和文件名提供给 attach_file 方法。

    希望这会对你有所帮助。

    【讨论】:

    • file_detector 的全部意义在于您不需要解决将文件放到远程计算机上的问题 - Selenium 应该为您处理从本地到远程的上传。
    • 感谢@ThomasWalpole 提供的信息。对我来说是新的学习,但上述解决方案确实对我有用。
    【解决方案3】:

    假设错误消息是来自远程驱动程序的响应(堆栈跟踪将有助于确认)错误消息包含原始文件名(而不是临时文件名)的事实告诉您文件检测器不是用过的。从您的代码中,不清楚 Capybara.current_session 在您的规范帮助程序代码运行时是什么,因此可能的原因是当您添加文件检测器时当前会话不正确。尝试在驱动程序注册块中设置它

    Capybara.register_driver(...) do
      ...
      Capybara::Selenium::Driver.new(app,
                                       browser: :remote,
                                       url: url,
                                       desired_capabilities: capabilities).tap do |driver|
        driver.browser.file_detector = lambda do |args|
          str = args.first.to_s
          str if File.exist?(str)
        end
      end
    end
    

    selenium-webdriver 3.14 版本中还针对file_detector 进行了一些工作,因此您可能也想尝试升级。

    另外,您是否尝试过使用 Capybaras attach_filemake_visible 选项而不是滚动您自己的 expose_file_upload

    page.attach_file(File.expand_path(path + file_name), make_visible: true)
    

    【讨论】:

      【解决方案4】:

      我偶然发现了这个线程的另一个错误,但发现这个问题的上下文很有用。将其添加到此处以防万一有人对此感到困惑:

      NoMethodError:
                 undefined method `file_detector=' for #<Selenium::WebDriver::Chrome::Driver:0x00007ff8edf60020>
      

      我的版本设置如下:

      • ChromeDriver 83.0.4103.39
      • selenium-webdriver 3.14

      解决这个问题:

      1. 我按照 Thomas 的建议将 driver.browser.file_detector 放入用于远程驱动程序的驱动程序注册中,如他的回答所示
      2. 我将 selenium-webdriver gem 从 3.14 升级到 3.142.7

      【讨论】:

        猜你喜欢
        • 2019-07-15
        • 1970-01-01
        • 2017-06-16
        • 1970-01-01
        • 2019-07-12
        • 2020-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多