【问题标题】:Is it possible to test the order of elements via RSpec/Capybara?是否可以通过 RSpec/Capybara 测试元素的顺序?
【发布时间】:2012-01-15 10:50:45
【问题描述】:

我使用 RSpec/Capybara 作为我的测试套件。我有一些 javascript 动态地将<li> 附加到<ul> 的末尾。我想编写一个请求规范以确保发生这种情况。

我尝试使用 has_css Capybara 方法和高级 CSS 选择器来测试 <li> 元素的顺序,但 Capybara 不支持 + CSS 选择器。

例子:

page.should have_css('li:contains("ITEM #1")')
pseuo_add_new_li
page.should have_css('li:contains("ITEM #1")+li:contains("ITEM #2")')

有没有人知道另一种测试订购的方法?

【问题讨论】:

    标签: ruby-on-rails-3 rspec ruby-on-rails-3.1 capybara


    【解决方案1】:

    由于page.body.should 已被弃用,我们可以使用正则表达式匹配进行多行比较,就像Ben 在那边的评论中所说:

    expect(page.body).to match /#{item1.name}.*#{item2.name}/m
    

    【讨论】:

      【解决方案2】:

      在上述解决方案中,如果页面上有多个元素,则很难测试顺序。所以,我找到了另一种方法。

      我已经在这里发布了解决方案 - Test order(sequence) of content using capybara

      映射具有 css 特定元素的数组,然后将该数组与预期的数组匹配(保持元素顺序)

      【讨论】:

      • 在 OP 的情况下,我认为这是一个等待发生的不稳定测试。如果在添加新元素的 javascript 之前页面上至少已经存在一个元素,则映射特定元素将立即仅返回页面上当前存在的那些元素,如果 javascript 花费太长时间,则可能不包括新元素。正如其他答案所建议的那样,最好是明确的并使用位置伪类选择器。
      【解决方案3】:

      您可以使用allfinder 方法选择多个元素,然后使用collect 将文本拉出到一个数组中:

      assert_equal page.all('#navigation ul li').collect(&:text), ['Item 1', 'Item 2', 'Item 3']
      

      如果您的列表在页面上不可见,例如弹出导航菜单,则需要将visible: false 传递给all 方法。

      【讨论】:

        【解决方案4】:

        使用前面提到的article的作者写的orderlygem

        很简单:

        expect(this).to appear_before(that)
        

        【讨论】:

          【解决方案5】:

          使用capybara-ui,您可以使用#widgets 方法以自上而下的顺序获取所有元素。

          # First define the widget,
          # or reusable dom element reference.
          # In this case in a role
          class UserRole < Capybara::UI::Role
            widget :list_item, '.list-item'
          end
          
          # Then test the expected order using #widgets
          role = UserRole.new
          expected_order = ['buy milk', 'get gas', 'call dad']
          actual_order = role.widgets(:list_item).map(&:text)
          
          expect(actual_order).to eq(expected_order)
          

          【讨论】:

            【解决方案6】:

            我最近遇到了同样的问题,并找到了这个简洁而理想的解决方案: http://launchware.com/articles/acceptance-testing-asserting-sort-order

            它甚至被包装成一个小宝石。

            【讨论】:

            • 谢谢 - 那篇文章对我很有帮助(我们使用的是 Minitest,而不是 RSpec)
            【解决方案7】:

            this article 列出了几种在 RSpec 中测试排序顺序的方法,其中最好的似乎是这个匹配器:

            RSpec::Matchers.define :appear_before do |later_content|
              match do |earlier_content|
                page.body.index(earlier_content) < page.body.index(later_content)
              end
            end
            

            【讨论】:

            • 使用 Webrat 我得到“未定义的局部变量或方法‘页面’”
            • @JoaoHornburg 抱歉,我无能为力。到目前为止我只用过水豚。
            • 我已经让它与 webrat 一起工作。已经在 github 上 fork 项目,等我有时间修改文档和发布 gem 时会发布我的代码
            • 我正在使用它,它可以工作。我想检查特定 div 中项目的顺序,应该怎么做?
            • 这篇文章非常适合进一步了解。
            【解决方案8】:

            这个页面有一个非常聪明的方法来测试页面上字符串元素的顺序——不管它们是否在列表中:

            https://makandracards.com/makandra/789-match-strings-in-a-given-order-with-cucumber-and-capybara

            它采用黄瓜步骤的形式,但您应该能够提取 Rspec 步骤所需的内容。它类似于 Johns 的“kludgy”解决方案——但从我能理解的情况来看有点花哨。他们所有其他狡猾的水豚测试步骤都可以在这里找到:

            https://github.com/makandra/spreewald

            【讨论】:

              【解决方案9】:

              我发现了一种使用 CSS 测试这种行为的更规范的方法。您可以在任何您喜欢的断言中使用:first-child:last-child:nth-child(n) 选择器。

              在你的例子中,我会尝试这些断言:

              page.should have_tag("ul:last-child", :text => "ITEM #1")
              pseuo_add_new_li
              page.should have_tag("ul:nth-last-child(2)", :text => "ITEM #1")
              page.should have_tag("ul:last-child", :text => "ITEM #2")
              

              我希望这对某人有所帮助。 Read more about this.

              【讨论】:

              【解决方案10】:

              我通过针对页面正文内容测试正则表达式匹配解决了这个问题。有点笨拙,但它有效。

              page.body.should =~ /ITEM1.*ITEM2.*ITEM3/
              

              【讨论】:

              • 和普通的Minitestassert page.body =~ /ITEM1.*ITEM2.*ITEM3/
              • 你也可以检查标签的结尾:expect(page) =~ &gt;ITEM1&lt;.*&gt;ITEM2&lt;.*&gt;ITEM3&lt;
              • 谢谢,非常优雅的解决方案。我最终将expect(response.body).to match(/ITEM1.*ITEM2.*ITEM3/m) 与 RSpec 4 和多行匹配一起使用
              • 有人能解释一下ITEM 在这些例子中代表什么吗?这些是类名吗?
              【解决方案11】:

              Capybara 应该支持+ 选择器(我相信它使用了 Nokogiri,它当然支持这一点)。您可能使用的是旧版本吗?或者您使用的是不支持 JavaScript 的 Capybara 驱动程序,因此根本不会渲染额外的元素?

              另外,不要使用 RSpec 来测试你的 HTML。黄瓜在这方面要好得多。为了与 JavaScript 交互,您需要使用 Selenium 或 Capybara-Webkit。或者,如果您有很多 JavaScript,请考虑使用 Jasmine 对其进行测试。

              【讨论】:

              • 我不知道您为什么投了反对票,但您完全正确地认为 Capybara(好吧,Nokogiri)支持 + 选择器。我怀疑新的li 没有被相邻添加到ITEM #1,他应该改用~ 选择器。
              • 黄瓜如何更好地测试html?
              • @DrewV Cucumber 更擅长以面向用户的术语对面向用户的内容进行断言。 RSpec 在测试 UI 时处于错误的抽象级别。
              猜你喜欢
              • 1970-01-01
              • 2015-02-20
              • 1970-01-01
              • 1970-01-01
              • 2015-04-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多