【问题标题】:Proper way to wait for a second page to load with Capybara when the first has the same field as the second当第一个页面与第二个具有相同的字段时,等待第二个页面加载 Capybara 的正确方法
【发布时间】:2014-01-23 16:27:01
【问题描述】:

我在访问两个表单上具有相同字段(“电子邮件”)的两个表单时遇到了问题。如果我不手动休眠,Capybara 似乎会在测试的第二部分的第一次访问中找到“电子邮件”字段。

# visit the first form and fill out a subscription
visit new_front_form_subscription_path(@web_form_1.id)
fill_in "Email", with: "subscriber@example.com"
fill_in "Field 1", with: "my first data"
click_button "Subscribe"

# visit the second form and fill out a subscription
visit new_front_form_subscription_path(@web_form_2.id)
sleep 1
fill_in "Email", with: "subscriber@example.com"
fill_in "Field 2", with: "my second data"
click_button "Subscribe"

随着睡眠的到来,规范以绚丽的色彩通过。没有睡眠,第二个表单提交会出现验证错误——归咎于空白的“电子邮件”值。

有没有合适的方法来处理这个问题?我不喜欢在规范中引入手动睡眠。

【问题讨论】:

    标签: rspec capybara rspec2


    【解决方案1】:

    您可以使用以下几种方法来解决它:

    1. 使用仅出现在第二页的另一个定位器来选择“电子邮件”字段:

      find('#second_page #email').set('subscriber@example.com')
      
    2. 编写一个语句来等待第二个页面被加载而不是休眠:

      visit new_front_form_subscription_path(@web_form_2.id)
      expect(page).to have_css('locator_present_only_at_second_page')
      fill_in "Email", with: "subscriber@example.com"
      

    【讨论】:

    【解决方案2】:

    上述答案是正确的,但如果您有一个大型测试套件,则难以实施,因为您必须在每个页面上找到一个独特的元素。如果您是 Michael Hartl 轨道学校的毕业生,那么有一个简单的方法可以解决这个问题。 Hartl 教授为每个控制器操作设置不同的 @title 实例变量。然后在 application.html.erb 中使用它来为每个页面设置一个 html 标题元素。

    我当然会这样做,并且它提供了一种非常简单的方法来修复我所有因页面未正确加载而失败的易碎测试。您找不到标题标签,因为它不可见。所以我所做的就是在application.html.erb的底部放了如下代码;

    <%= content_tag :div, "[#{title}]", class: 'rspec_eyes_only' if Rails.env.test? %>
    

    如果您处于测试模式,这将插入一个带有标题文本的 div,并用方括号括起来。然后我在 rails_helper.rb 中写了一个助手

    def wait_for_page_load(title)
      find('div.rspec_eyes_only', text: title)
    end
    

    我已经有另一个助手来测试正确的标题,所以我修改它以添加 wait_for_page_load 即;

    def title_is_correct(title)
      full_title = "#{BaseTitle} | #{title}"
      wait_for_page_load "[#{full_title}]"
      expect(page.title).to eq full_title
    end
    

    这些简单的更改几乎清除了我所有不稳定的测试。

    【讨论】:

      【解决方案3】:

      如果您使用上述 Andrey 的 2),您可能需要查看 holdon gem,这将允许您编写一个等待元素加载的块,然后移至 fill_in 方法一次元素加载。

      【讨论】:

      • e = HoldOn.until(timeout: 60, interval: 5) { s.first(:css, "div#bastard") } 的等效项是 e = find('div#bastard', wait: 60, match: :first)。 Holdon gem 是完全没有必要的。但我不想通过:match param: find('div#bastard', wait: 60)
      【解决方案4】:

      一般情况下,可以这样做。例如,要单击在加载模式弹出窗口(或其他页面)后找到的按钮,请将以下块添加到您的宏文件中。

      def wait_until_modal
         page.has_css?('.modal')
      end
      

      这里的类 .modal 可以在弹出页面上找到。

      【讨论】:

        【解决方案5】:

        尝试在新页面加载后的第一行添加, wait: 10

        visit new_front_form_subscription_path(@web_form_2.id)
        fill_in "Email", with: "subscriber@example.com", wait: 10 # <--
        

        我刚遇到类似情况:

        visit promo_path
        fill_in 'promo_code', with: 'HALFPRICEPROMO'
        click_button 'Activate' # onClick does things and eventually loads the next page
        assert page.has_content? 'Confirm your email address', wait: 10 # <--
        

        如果没有上面的wait,任何和所有断言都会失败。我把10 放得更安全了; 3 似乎是我的情况的最低要求。

        我在这里找到了答案:Make capybara wait until Ajax finishes

        【讨论】:

          【解决方案6】:

          使用 SitePrism,您可以使用 wait_until_true 来测试 current_url

          new_path = new_front_form_subscription_path(@web_form_2.id)
          visit new_path
          wait_until_true { current_url.include? new_path }
          fill_in "Email", with: "subscriber@example.com"
          fill_in "Field 2", with: "my second data"
          click_button "Subscribe"
          

          【讨论】:

            【解决方案7】:

            我将它用于页面转换:

            visit page1
            
            do_something
            
            visit page2
            
            Timeout.timeout(Capybara.default_max_wait_time) do
              sleep(0.1) until current_url.include?(page2)
            end
            
            do_something_else
            

            【讨论】:

              【解决方案8】:

              “时间戳” 方法。更改您的布局文件(例如application.html.haml)以提供时间戳:

              %body{"data-rendered-at" => Time.now.to_f.to_s}
              

              然后创建一个辅助方法来等待页面卸载:

              # in capybara_helper.rb
              def with_waiting_unload(&block)
                current_rendered_at = find('body')['data-rendered-at']
                yield
                expect(page).not_to have_css("body[data-rendered-at='#{current_rendered_at}']")
              end
              

              最后你的代码将是:

              # (snip)...
              with_waiting_unload do
                  visit new_front_form_subscription_path(@web_form_2.id)
              end
              sleep 1
              fill_in "Email", with: "subscriber@example.com"
              # ...(snip)
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-09-18
                • 1970-01-01
                • 1970-01-01
                • 2012-05-23
                • 2023-04-02
                • 1970-01-01
                相关资源
                最近更新 更多