水豚不等待 ajax 请求

capybara not wait ajax request

我在 rspec + capybara + poltergeist 中收到以下错误:

given!(:user_owner) { create(:user) }
given!(:second_user) { create(:user) }
given!(:question) { create(:question, user: user_owner) }

describe 'as not question owner' do
  before do
    login_as(second_user, scope: :user, run_callbacks: false)
    visit question_path(question)
  end

  scenario 'can upvote just one time', js: true do
    first('a#question-upvote').click
    expect(first('div#question-score').text).to eq '1'
    first('a#question-upvote').click
    expect(first('div#question-score').text).to eq '1'
  end

Failure/Error: expect(page.first('div#question-score').text).to eq '-1'

   expected: "-1"
        got: "0"

当我插入睡眠 1 时:

scenario 'can upvote just one time', js: true do
   first('a#question-upvote').click
   sleep 1
   expect(first('div#question-score').text).to eq '1'
   first('a#question-upvote').click
   sleep 1
   expect(first('div#question-score').text).to eq '1'
end

测试通过。

我了解到页面未等待异步请求。 如何重写测试以使其在不睡觉的情况下正常工作?

P.S。对不起英语。

您正在使用 eq 匹配器终止任何等待行为。这是因为一旦你在找到的元素上调用 .text 你就有了一个 String 并且在与 eq 匹配器一起使用时无法 reload/re-query 该字符串。如果你想要 waiting/retrying 行为,你需要使用 Capybara 提供的匹配器和 Capybara 元素。

所以你应该

而不是 expect(first('div#question-score').text).to eq '1'
expect(first('div#question-score')).to have_text('1', exact: true) # you could also use a Regexp instead of specifying exact: true

另一件需要注意的事情是 all/first 禁止重新加载元素,所以如果整个页面都在变化(或者你正在等待文本的元素被完全替换)并且初始页面有一个与选择器匹配的元素,但您实际上想要检查第二页(或替换元素)中的元素,您不应该使用 first/all - 在这种情况下您可能希望将 find 与使用 css :first-child/:first-of-type 等类型的事物(或等效的 XPath)的查询一起使用来唯一标识您的元素,而不是返回倍数和选择其中之一。如果只是页面上被异步替换的元素的值那么你不用担心。