2012-03-27 59 views
9

我使用rspec 2.6.0和Capybara 1.1.1進行驗收測試。
隨着像下面這樣的觀點:水豚和Rspec:在()和have_selector()中一起使用的正確方法?

<tr > 
    <td>Team 3 Name</td> 
    <td>true</td> 
    <td><a href="/teams/3">Show</a></td> 
    <td><a href="/teams/3/edit">Edit</a></td> 
    <td><a href="/teams/3">Deactivate</a></td> 
</tr> 
<tr > 
    <td>Team 4 Name</td> 
    <td>true</td> 
    <td><a href="/teams/4">Show</a></td> 
    <td><a href="/teams/4/edit">Edit</a></td> 
    <td><a href="/teams/4">Deactivate</a></td> 
</tr> 

我想寫的驗收測試,指出:「團隊3不具備‘停用’的鏈接。」我期望以下失敗:

within('tr', :text => 'Team 3 Name') do |ref| 
    page.should_not have_selector('a', :text => 'Deactivate') 
end 

但它通過。爲了進一步測試發生了什麼,我寫了荒謬:

lock = false 
within('tr', :text => 'Team 3 Name') do |ref| 
    page.should have_selector('a', :text => 'Deactivate') 
    page.should_not have_selector('a', :text => 'Deactivate') 
    lock = true 
end 
lock.should be_true 

哪些也通過。

我從這裏假定,調用的has_selector()調用的作用域不受intra()塊的限制,但我不確定這是爲什麼。水豚文檔使用這種模式,似乎沒有提及任何陷阱。 什麼是正確的方式來限制我的選擇範圍? 謝謝。 /Salernost

+0

你檢查,看看是否'page'是零通過一些奇怪的巧合,還是放在一個調試器在測試的頂部行,以便您可以進入控制檯並輸出「page」的值,或者添加步驟「並顯示頁面」,以便您的瀏覽器向您顯示處於所處狀態的頁面副本在它運行這個測試之前?如果是這樣,測試框架實際上看到了什麼? – jefflunt 2012-03-27 21:48:24

+0

感謝您的回覆。我可以通過調試輸出來驗證頁面是否爲零,而且當我在within()塊內調用「puts ref.text」時,我會得到正確的:「Team 3 Name true Show Edit Deactivate」。請注意,我在()中使用了猴子補丁來生成上下文,以便我可以在其上調用文本。我在()之後進行了修補,但之後我發現了這種奇怪的行爲,因此不是根本原因。 :) – salernost 2012-03-28 01:15:44

+0

[此主題](https://groups.google.com/forum/?fromgroups#!topic/ruby-capybara/1sdsA7nubyE)可能會引起您的興趣。 – 2012-03-29 00:03:05

回答

10

還在學習水豚本人,但你試過have_link而不是have_selector?我也不認爲你需要|ref|。例如:

lock = false 
within('tr', :text => 'Team 3 Name') do # omit |ref| 
    page.should have_link('Deactivate') 
    page.should_not have_link('Deactivate') 
    lock = true 
end 
lock.should be_true 


更新2012年10月13日

已經來了一點點進一步與水豚,我在這裏看到一些潛在的問題:

  • within可以靜靜地忽略了text領域。您會注意到這些示例僅顯示不帶額外參數的CSS或XPath查找器。
  • 如果within的確使用text,它可能無法在這裏工作,因爲您要求它查看<tr>,但文本位於<td>
  • 即使您在within區塊中,page主題仍然可以定位整個頁面。 within的例子主要是關於使用fill_inclickBeware the XPath // trap下的例子是例外。

與創建within塊,你可以給你的錶行的唯一ID和使用CSS搜索它們,或者你可以寫一個特定的XPath針對第一個匹配行。

後者的問題在於,您希望在<tr>上使用within,但是您用於定位的文本位於<td>子元素中。因此,例如,此XPath應該找到包含文本Team 3 Name的表格單元格,但那麼您只能在第一個單元格中操作within,而不是整行。

within(:xpath, "//tr/td[normalize-space(text())='Team 3 Name'") do 

有辦法「備份」的父元素使用XPath,但我不知道該怎麼做,我讀過,這不是好的做法。我想在這裏你最好的選擇可能是剛纔生成的ID,這樣你行這樣開始:

<tr id="team_3"> 

然後用一個簡單的

within("tr#team_3") 
+1

謝謝馬克。不幸的是,has_link不會改變錯誤的行爲。另外你是正確的,我不需要'ref',我也沒有看到這個問題。上面的代碼是在錯誤跟蹤中複製的。(實際上,我需要修補水豚讓我得到塊,無論如何...)進一步的調查似乎表明,這個錯誤與within()調用有關。當我在('tr#some_id')內使用時,由於身份規則,行爲會失敗。我覺得這是水豚部分的一個錯誤,因爲文檔中明確指出within()調用將與頁面上的one/first匹配 – salernost 2012-04-09 20:14:31

4

have_selector似乎忽略:text:content選項對其進行定位。我不得不使用這樣的事情,而不是:

within 'a' do 
    page.should have_content 'Deactivate' 
end 
2

我也建議Mark Berry的他提到加入ID對每個表元素的最終辦法。

<tr id="team_3"> 

則應以

within("tr#team_3") 

水豚已經給在似乎不工作始終XPath的選擇時,特別是與CI服務我的問題。

我也想在相同的答案要注意本節:

這很可能是網頁主題還是針對即使你是在一個塊內的整個頁面。其中的例子主要是關於使用fill_in或click。例外是小心XPath //陷阱下的例子。

這可能是在舊版本的情況下,但在水豚的當前版本中,調用page一個within塊內只檢查目標頁面的一部分。因此,使用馬克的上面的例子:

within("tr#team_3") do 
    expect(page).to have_content 'Team 3 Name' 
    # => true 
    expect(page).to have_content 'Team 4 Name' 
    # => false 
end 
1

解決辦法是不使用within方法:

expect(page).to have_css('tr#team_3') do 
    without_tag('a', text: 'Deactivate') 
end