【问题标题】:Capybara doesn't wait till the end of file uploadCapybara 不会等到文件上传结束
【发布时间】:2021-02-23 20:17:57
【问题描述】:

我正在用 Ruby 和 Capybara 编写脚本。这个脚本应该上传一个文件,一旦文件上传,脚本应该点击“保存”按钮。 我成功地使文件开始上传,但几秒钟后脚本就停止了。最后,文件没有上传,我需要从头开始。

页面上有一个“保存”按钮,该按钮在文件上传之前一直处于禁用状态。所以我尝试用它的状态作为指标。但是水豚不认识它。

我的代码:

upload_btn = browser.all(:element, 'span', text: 'Upload')
browser.attach_file($app_path) do
  upload_btn[0].click
end
browser.has_button?('Save', wait: 200)
browser.click_on('Save')

页面的 UI 是什么样子的(抱歉截图):

我认为它不起作用,因为它不是 button 而是 material-button 并且 Capybara 无法识别此元素。使用类/ID 不是最好的主意,因为所有类都是动态的,我不能指望它

您能建议在这里可以做什么吗?或者我如何让水豚等到这个按钮被禁用?

谢谢!

【问题讨论】:

    标签: ruby capybara


    【解决方案1】:

    现在 OP 已经发布了他们的完整方法,对于以后提出这个问题的任何人,请不要像当前接受的答案那样编写 Capybara 代码。

    1. 当您只关心first 元素时,不要使用all

    2. 当你真的不需要它时不要使用 :element 选择器类型

    3. 不要仅仅为了等待而使用谓词方法

    4. 比起只是睡觉更喜欢期望/断言

    这归结为更像

    def create_release
      puts('Create release and upload APK')
      browser.find('div[role="menuitem"]', text: 'Production').click
      browser.first(:button, 'Create new release').click
    
      #OPT out
      browser.click_button('Manage preferences', wait: 200) # 200 seems like a really long max wait time here
      browser.choose('Opt out of app signing by Google Play')
      browser.click_button('Update', wait: 100) # again - seems really long
    
      browser.first(:button, 'Opt out', wait: 500).click # and again
    
      #File upload part and saving
      browser.attach_file($app_path) do
        browser.first('span', text: 'Upload').click
      end
    
      expect(browser).to have_selector(:element, 'material-button', text: 'Save', disabled: false, wait: 200)
      browser.first(:button, 'Save', wait: 300).click
    
      expect(browser).to ... # whatever change clicking the button triggers 
    end
    

    【讨论】:

      【解决方案2】:

      假设is_disabled 类和disabled 属性在按钮变为活动状态时被删除,那么您可以使用以下任何一种(假设 200 秒足以完成上传)

      find('material-button:not([disabled])', text: 'Save', wait: 200).click
      find('material-button:not(.is_disabled)', text: 'Save', wait:200).click
      find('material-button', class: '^is_disabled', text: 'Save', wait: 200).click # The ^ in front of the class name indicates to negate
      

      如果debug-id 可用且稳定,则可以跳过text 选项,这样会更有效

      find("material-button[debug-id='save-button']:not([disabled])", wait:200).click
      

      最后一个选择是使用 Capybara :element 选择器类型

      find(:element, 'material-design', 'debug-id': 'save-button', disabled: false, wait: 200).click
      find(:element, 'material-design', disabled: false, text: 'Save', wait: 200).click
      

      【讨论】:

      • 不是我是专家,但等待真的有必要吗?似乎(根据我的阅读)水豚会自动等待 find 直到匹配发生。
      • @engineersmnky 默认情况下,Capybara 将等待 Capybara.default_max_wait_time 满足条件。默认为 2 秒,根据用于测试的硬件,通常设置在 1-5 秒范围内。根据原始帖子,我假设上传未在该范围内完成,因此包括wait 选项。这是一个最长等待时间,所以当满足条件时它会继续(即它不会等待完整的 200)所以最坏的情况是如果/当上传实际失败时它会延迟失败案例。
      • 完美。认为我受启发。感谢您的澄清,现在我知道我将来是否需要使用水豚。
      • 我的转变与你写的有点不同。但最接近的是您提出的最后一个变体。我现在将在下面发布解决方案。谢谢你的建议,伙计们!
      【解决方案3】:

      所以,周转可能不是最专业的,但至少它奏效了,我现在可以自动化一些事情。

      基本上,我使用has_button? 让我的脚本等到APK 文件被上传。文件上传 200 秒就足够了(统计上)。 最后,脚本暂停了,但为了安全起见,我决定最后添加sleep 3

      这是为我上传 APK 的功能。也许有人会需要它

       def create_release
         puts('Create release and upload APK')
         browser.find(:element, 'div', role: 'menuitem', text: 'Production').click
         create_release_btn = browser.all(:button, text: 'Create new release')
         create_release_btn[0].click
      
         #OPT out
         browser.click_button('Manage preferences', wait: 200)
         sleep 2
         browser.choose('Opt out of app signing by Google Play')
         browser.click_button('Update', wait: 100)
         sleep 3
         op_out_btn = browser.all(:button, text: 'Opt out', wait: 500)
         op_out_btn[0].click
         sleep 4
      
         #File upload part and saving
         upload_btn = browser.all(:element, 'span', text: 'Upload')
         browser.attach_file($app_path) do
           upload_btn[0].click
         end
         save_btn = browser.all(:element, 'material-button', text: 'Save', disabled: false, wait: 200)
         browser.has_button?(save_btn, disabled: false, wait: 200)
         button_test = browser.all(:button, text: 'Save', wait: 100)
         button_test[0].click
      
         sleep 3
      end
      
      

      【讨论】:

        猜你喜欢
        • 2016-01-09
        • 1970-01-01
        • 1970-01-01
        • 2021-06-25
        • 2014-02-15
        • 2019-04-26
        • 1970-01-01
        • 2019-05-21
        • 2013-06-26
        相关资源
        最近更新 更多