RSpec:在不同情况下执行相同的期望

RSpec: execute the same expectation under different circumstances

我想确保我网站上的某个元素仅在登录时显示。

我目前是这样实现的:

it 'displays statistics when logged in' do
  expect {
    login_as(create :user)
    refresh_page
  }.to change {
    page.has_content? 'Statistics'
  }.from(false).to true # I know, "to true" is redundant here, but I like it to be explicit
end

这有点笨拙。特别是,当规范失败时,我没有收到通常在执行 expect(page).to have_content 'Statistics' 时收到的漂亮错误消息,我只是收到类似 "expected result to have changed from false to true, but did not change" 的信息,这不是很有用。

我知道有共享的例子,但对于这个案例来说他们感觉有点太多了。

我尝试了类似下面的方法,但也没有成功:

it 'displays statistics when logged in' do
  expect(expect_to_have_content_statistics).to raise_error

  login_as(create :user)
  refresh_page

  expect_to_have_content_statistics
end

def expect_to_have_content_statistics
  expect(page).to have_content 'Statistics'
end

有什么想法吗?我不想写2次期望,因为这很容易出错。

您正在测试两种不同的情况 - 建议将它们分开。

describe 'statistics' do

  def have_statistics
    have_content('Statistics')
  end

  before { visit_statistics_page }

  it { expect(page).to_not have_statistics }

  it 'displays statistics when logged in' do
    login_as(create :user)
    expect(page).to have_statistics
  end
end

我会将规范分成两个 context 块,因为您正在测试两个不同的用例。此外,不是对 page 进行基于文本的硬编码 have_content 检查,您是否使用某种 <div><span> 标签来包装统计内容(使用也许是 classid 之类的 statistics 之类的)?如果没有,您可能需要考虑一个,如果是,则考虑更改您的规范以根据用户是否登录来检查该选择器是否存在:

RSpec.feature 'Statistics' do
  context 'when user is not logged in' do
    before do
      visit statistics_path # or whatever path this is
    end

    it 'does not display the statistics' do
      expect(page).to_not have_selector('.statistics')
    end
  end

  context 'when user is logged in' do
    before do
      login_as(create :user)
      visit statistics_path # or whatever path this is
    end

    it 'displays the statistics' do
      expect(page).to have_selector('.statistics')
    end
  end
end