【问题标题】:Capybara not finding content on page when it should?Capybara 什么时候没有在页面上找到内容?
【发布时间】:2021-04-30 13:19:11
【问题描述】:

我正在使用 Capybara,我正在使用以下命令从下拉列表中选择一个项目:

select "Some Option", from: "client_id", visible: :all

这是我用来生成选择的视图代码:

<%= form_with(url: '#', method: 'GET') do |f| %>
    <%= f.select :client_id,
        options_for_select(
            Client.accessible_by(current_ability)
            .map{|c| [c.name, c.id]}, selected_client_id
        ),
        {include_blank: defined?(include_blank) ? include_blank : false},
        {
            class: "form-control selectpicker border",
            id: "client_id",
            onchange: "this.form.submit()",
            data: {'live-search': true, style: "btn-white"}
        } 
    %>
<% end %>

当我自己在页面上与之交互时,它可以正常呈现并按预期工作。

我认为问题源于此:onchange: "this.form.submit()"

当 Capybara 从 select 中选择一个选项时,它应该提交表单,然后页面应该使用查询字符串 /?client_id=X 重新加载,但这不是正在发生的事情,我不知道为什么。

当我查看错误提供的屏幕截图时,似乎 Capybara 甚至没有从下拉列表中选择任何内容,它只是说“未选择任何内容”。


这是水豚测试:

    def check_grand_total(expected_value)
        visit current_path

        click_link "Balance"

        # it seems as though Capybara is not waiting for this to finish... but I don't know, just my theory
        # this is supposed to trigger: this.form.submit() on the dropdown
        select "Some Client", from: "client_id", visible: :all 

        actual_value = page.first('.grand-total').text
        assert_equal(expected_value, actual_value)
    end

错误:

E

Error:
OrdersTest#test_deposit_orders:
Capybara::ExpectationNotMet: expected to find css ".grand-total" at least 1 time but there were no matches
    test/system/helpers/balance_test_helper.rb:10:in `check_grand_total'
    test/system/orders_test.rb:113:in `block in <class:OrdersTest>'

我在想也许 Capybara 出于某种原因实际上并未触发 change 事件。

【问题讨论】:

  • @engineersmnky 确定添加

标签: ruby-on-rails capybara


【解决方案1】:

所以我认为问题在于 onchange 甚至没有真正触发 This "issue" 建议通过

fill_in("foo", with: "hello world").send_keys(:tab)

所以有可能适应

select("Some Client", from: "client_id", visible: :all).send_keys(:tab)

话虽如此,似乎也存在一种方法来强制Element Capybara::Node::Element#trigger 上的事件,所以我将从尝试开始:

select("Some Client", from: "client_id", visible: :all).trigger(:onchange)

免责声明:我对水豚不是很熟悉,所以这个答案是基于源审查和谷歌搜索。根据Thomas Walpole,显然有extensive experience“大多数驱动程序不支持trigger,因为在测试期间使用它没有多大意义,因为它不能复制用户会真的。”

【讨论】:

  • 奇怪的是,onchange 事件似乎有时会触发,但有时却不会。我会尝试你的建议,如果它不起作用,我会告诉你,谢谢!
  • trigger 不受大多数​​驱动程序的支持,因为在测试期间使用它没有多大意义,因为它不能复制用户实际执行的操作。
【解决方案2】:

您指定的类名,以及您指定的事实(可见::all)意味着您可能正在使用某种类型的 JS 小部件来替换标准的 html 选择元素。真的吗?在 Capybara 操作中覆盖可见性检查没有任何意义,因为您不应该与不可见的元素进行交互,并且具体取决于哪个操作和驱动程序会出错,或者不做任何事情。如果您使用的是替换小部件,那么您需要与小部件创建的元素进行交互,而不是使用select

如果你没有使用 JS 小部件,那么它可能只是一个写得不好的测试。马上有几件事 - 首先是您正在访问 current_path,其次是您正在针对文本进行断言,而不是使用 Capybara 提供的断言之一。需要记住的是浏览器操作是异步发生的,所以当你告诉 Capybara 从一个选择元素中选择一个选项时,不能保证当select 调用返回时触发的操作已经完成。因此,您应该使用 capybara 提供的断言/期望,其中包括等待/重试行为,以便将浏览器与测试同步。

def check_grand_total(expected_value)
    # This visit looks dangerous because it's not guaranteed to have changed 
    # the page when the `visit` returns, which means it may try and click
    # the link on the previous page. You should really be checking for something
    # that wouldn't be on the previous page -- It's also strange that there is a current path since tests should be independent
    visit current_path 

    click_link "Balance" # see above comment

    select "Some Client", from: "client_id"

    # This will wait up to Capybara.default_max_wait_time seconds for 
    # the grand total element to contain the expected text
    assert_selector '.grand-total', exact_text: expected_value
    # If using RSpec it would be
    # expect(page).to have_selector '.grand-total', exact_text: expected_value
end

【讨论】:

  • 这是一个替换小部件,我正在使用引导选择。我相信它会围绕
  • @BlaineLafreniere 我最近没有看过 bootstrap-select 但它可能会隐藏原始的 html 选择并在页面中创建它自己的元素以显示给用户。如果是这种情况,您需要与 bootstrap-select 创建的元素进行交互。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多