我找到了一个来自两个约束的解决方案:
- 我不认为您可以在 Capybara 中安全地调用driver.quit而不获得对私有@session_pool的访问权限,因为 Capybara 无法让用户一旦将会话从池中删除。因此,如果您调用 driver.quit 。退出会话,您无法从池中删除该会话,最终 Capybara 将尝试重置!会话,导致 Poltergeist 抛出 IOError,因为它通过 websockets 的内部通信未连接。
- 如果您在每次测试运行后都敲击整个会话池,并在执行此操作时退出每个会话中的每个 poltergeist 驱动程序,最终您将遇到TOO MANY OPEN FILES错误。IE,:
重新创建 TOO MANY OPEN FILES 错误的方法——不要使用这个!!
# you have to do quite a few test runs to cause the open files error
config.append_after(:each) do
session_pool = Capybara.instance_variable_get("@session_pool")
session_pool.each do | key, value |
value.driver.quit
end
session_pool.clear
end
我相信这是一个真正的 poltergeist 错误,但我不在乎......这就是为什么......在运行上面的代码时,我注意到创建一个 poltergeist 会话是一个明显缓慢且资源密集型的操作。所以,我决定我宁愿有一个永远不会消失的会话池……Capybara 的设计方式。
这种方法的唯一问题是像我一样使用 Capybara.session_name ,即在每个测试的基础上提出任意测试名称。也许在一个测试中,我希望每个 session_name 与用户的数据库 ID 相同。或者也许我想出了我在整个测试中使用的 5 个常量,以及 5 个不同的常量用于不同的测试。换句话说,我可能会在我的测试套件中使用 100 个 session_name,但对于任何给定的测试,我最多只有少数几个会话。所以一个好的解决方案会重用 poltergeist 会话,但让我在每次测试运行时使用任意会话名称。
这是我的解决方案
规范/实用程序.rb
# holds a single test's session name's, mapped to pooled session names
$capybara_session_mapper = {}
# called after each test,
# to make sure each test run has it's own map of session names
def reset_session_mapper
$capybara_session_mapper.clear
end
# manages the mapped session name
def mapped_session_name(session_name)
return :default if session_name == :default # special treatment for the built-in session
$capybara_session_mapper[session_name] ||= $capybara_session_mapper.length
end
# in place of ever using Capybara.session_name directly,
# this utility is used to handle the mapping of session names in a way across all tests runs
def in_client(name)
Capybara.session_name = mapped_session_name(session_name)
yield
end
在 *spec_helper.rb* 中:
config.after(:each) do
Capybara.reset_sessions!
reset_session_mapper
end
直接使用 in_client 而不是 Capybara.session_name 的示例测试:
it "can't see a private thing until it is made public" do
in_client(user1.id) do
visit '/some/private/thing'
expect(page).to have_selector('#private-notice')
end
in_client(user2.id) do
visit '/expose/some/private/thing'
end
in_client(user1.id) do
visit '/some/private/thing`
expect(page).to have_selector('#private-content')
end
end
- 从我的 github 答案中复制