Capybara不遵循重定向和更改数据库

时间:2012-07-28 15:53:53

标签: ruby-on-rails ruby redirect rspec capybara

我有两个失败的规格,似乎有点相关。他们是:

describe "exclude from navigation button" do
  before do
      within "#page_#{pages[1].id}" do
      click_link I18n.t 'pages.exclude'
    end
    pages[1].reload
  end
  specify { pages[1].menu_order.should == -1 }
  it "should add an excluded css class to the pages control" do
    page.should have_selector "li.excluded#page_#{pages[1].id}"
  end
end

describe "include in navigation button" do
  before do
    within "#page_#{pages[2].id}" do
      click_link I18n.t 'pages.include'
    end
    pages[2].reload
  end
  specify { pages[2].menu_order.should == 1 }
  it "should remove the excluded css class from the pages control" do
    page.should_not have_selector "li.excluded#page_#{pages[2].id}"
  end
end

使用expected css "..." (not) to return (any|some)thing声明css(每个块的第二个示例)时,两个描述块都失败。

这是click_link操作的控制器代码:

def exclude_page
  page = Page.find params[:page_id]
  Hierarchy::PageHierarchy.exclude! page
  redirect_to admin_pages_path
end

def include_page
  page = Page.find params[:page_id]
  Hierarchy::PageHierarchy.include! page
  redirect_to admin_pages_path
end

这些是模块方法排除!并包括!:

def self.exclude! page
  page.update_attribute :menu_order, -1
end


def self.include! page
  page.update_attribute :menu_order, 1
  menu_order = 2
  page.siblings.each do |p|
    p.update_attribute :menu_order, menu_order unless p.menu_order == -1
    menu_order += 1
  end
end

这是重定向(admin_pages_path)目标的控制器代码:

def index
  @pages = Page.roots
end

Page.roots是where parent_id: nil的范围。

第一个示例块很容易修复。我只需要重新访问页面和CSS匹配。但afaik Capybara应该遵循重定向。那为什么我要重新访问?

第二个块更难(如果这值得自己提出问题,请打我,我只是想避免重复使用所有代码。)

这次重新访问页面不会有效。事实上,重新访问似乎改变了数据库:

    69:       end
    70:       pages[2].reload
    71:     end
    72:     its(:menu_order) { should == 1}
    73:     it "should add an excluded css class to the pages control" do
 => 74:       binding.pry
    75:       page.should_not have_selector "li.excluded#page_#{pages[2].id}"
    76:     end
    77:   end
    78: end

[1] pry(#<RSpec::Core::ExampleGroup::Nested_1::Nested_2>)> pages[2].id
=> 9
[2] ... > Page.find(9).menu_order
=> 1
[3] ... > visit admin_pages_path
=> nil
[4] ... > Page.find(9).menu_order
=> -1

这是我感到困惑的地方。所以我不明白的是: - 为什么我必须在第一个示例块中重新访问? - 为什么这个技巧在第二个示例块中不起作用? - 为什么要重新访问更改数据库的页面?

请注意,所有这些仅适用于Capybara / RSpec。使用浏览器手动执行此操作时,一切正常。

更新:

页面定义:

let(:pages) { bunch_of_pages.sort { |a, b| a.menu_order <=> b.menu_order } }

# bunch_of_pages:
def bunch_of_pages
  pages = []
  roots << root1 = FactoryGirl.create(:public_page, menu_order: (rand*1000).to_i)
  child1 = FactoryGirl.create :public_page, parent: root1, menu_order: (rand*1000).to_i
  child2 = FactoryGirl.create :public_page, parent: root1, menu_order: (rand*1000).to_i
  subchild1 = FactoryGirl.create :public_page, parent: child2, menu_order: (rand*1000).to_i

  pages << root2 = FactoryGirl.create(:public_page, menu_order: (rand*1000).to_i)
  child3 = FactoryGirl.create :public_page, parent: root2, menu_order: (rand*1000).to_i
  .
  .
  .

  pages
end

1 个答案:

答案 0 :(得分:0)

不确定为什么在没有重新加载页面的情况下测试没有通过。但是,编写第二个示例的正确方法是:

page.should have_no_selector "li.excluded#page_#{pages[2].id}"

Capybara的断言有一个内置机制,可以在失败前重试一次特定次数的匹配。它仅在您使用should而非should_not时才有效。