Capybara 透過模擬真實使用者如何與您的應用程式互動來幫助您測試 Web 應用程式。它與運行測試的驅動程式無關,並且內建 Rack::Test 和 Selenium 支援。
如果您和/或您的公司發現 Capybara 的價值並願意為其持續維護和開發提供資金,請造訪 Patreon
需要幫助嗎?詢問討論(請不要打開問題):https://github.com/orgs/teamcapybara/discussions/categories/qa
Capybara 需要 Ruby 3.0.0 或更高版本。若要安裝,請將此行新增至您的Gemfile
並執行bundle install
:
gem 'capybara'
如果您正在測試的應用程式是 Rails 應用程序,請將此行新增至您的測試幫助程式檔案:
require 'capybara/rails'
如果您正在測試的應用程式是 Rack 應用程序,而不是 Rails,請將 Capybara.app 設定為您的 Rack 應用程式:
Capybara . app = MyRackApp
如果您需要測試 JavaScript,或者您的應用程式與遠端 URL 互動(或位於遠端 URL),則需要使用不同的驅動程式。如果使用 Rails 5.0+,但不使用 5.1 中的 Rails 系統測試,您可能還需要將用於啟動應用程式的「伺服器」交換到 Puma,以符合 Rails 預設值。
Capybara . server = :puma # Until your setup is working
Capybara . server = :puma , { Silent : true } # To clean up your test output
cucumber-rails
gem 內建了 Capybara 支援。如果您沒有使用 Rails,請手動載入capybara/cucumber
模組:
require 'capybara/cucumber'
Capybara . app = MyRackApp
您可以在步驟中使用 Capybara DSL,如下所示:
When /I sign in/ do
within ( "#session" ) do
fill_in 'Email' , with : '[email protected]'
fill_in 'Password' , with : 'password'
end
click_button 'Sign in'
end
您可以透過使用@javascript
標記場景(或功能)來切換到Capybara.javascript_driver
(預設為:selenium
):
@javascript
Scenario : do something Ajaxy
When I click the Ajax link
...
還有為您設定的每個註冊驅動程式的明確標籤( @selenium
、 @rack_test
等)。
透過新增以下行(通常會新增到您的spec_helper.rb
檔案)來載入 RSpec 3.5+ 支援:
require 'capybara/rspec'
如果您使用的是 Rails,請將您的 Capybara 規格放在spec/features
或spec/system
中(只有在您在RSpec 中配置它時才有效),如果您將Capybara 規格放在不同的目錄中,則使用type: :feature
或type: :system
取決於您正在編寫的測試類型。
如果您使用 Rails 系統規範,請參閱其文件以選擇您想要使用的驅動程式。
如果您不使用 Rails,請使用type: :feature
。
現在您可以像這樣編寫規格:
describe "the signin process" , type : :feature do
before :each do
User . create ( email : '[email protected]' , password : 'password' )
end
it "signs me in" do
visit '/sessions/new'
within ( "#session" ) do
fill_in 'Email' , with : '[email protected]'
fill_in 'Password' , with : 'password'
end
click_button 'Sign in'
expect ( page ) . to have_content 'Success'
end
end
使用js: true
切換到Capybara.javascript_driver
(預設為:selenium
),或提供:driver
選項來切換到一個特定驅動程式。例如:
describe 'some stuff which requires js' , js : true do
it 'will use the default js driver'
it 'will switch to one specific driver' , driver : :selenium
end
Capybara 還附帶內建 DSL,用於建立描述性驗收測試:
feature "Signing in" do
background do
User . create ( email : '[email protected]' , password : 'caplin' )
end
scenario "Signing in with correct credentials" do
visit '/sessions/new'
within ( "#session" ) do
fill_in 'Email' , with : '[email protected]'
fill_in 'Password' , with : 'caplin'
end
click_button 'Sign in'
expect ( page ) . to have_content 'Success'
end
given ( :other_user ) { User . create ( email : '[email protected]' , password : 'rous' ) }
scenario "Signing in as another user" do
visit '/sessions/new'
within ( "#session" ) do
fill_in 'Email' , with : other_user . email
fill_in 'Password' , with : other_user . password
end
click_button 'Sign in'
expect ( page ) . to have_content 'Invalid email or password'
end
end
feature
其實只是describe ..., type: :feature
, background
是before
的別名, scenario
的it
,以及given
/ given!
let
/ let!
, 分別。
最後,視圖規格也支援 Capybara 匹配器:
RSpec . describe "todos/show.html.erb" , type : :view do
it "displays the todo title" do
assign :todo , Todo . new ( title : "Buy milk" )
render
expect ( rendered ) . to have_css ( "header h1" , text : "Buy milk" )
end
end
注意:當您需要安裝「capybara/rspec」代理程式方法來解決 Capybara::DSL 方法all
/ within
和同名內建 RSpec 匹配器之間的名稱衝突。如果您選擇不要求“capybara/rspec”,則可以透過在要求 RSpec 和“capybara/dsl”之後要求“capybara/rspec/matcher_proxies”來安裝代理方法
如果您使用Test::Unit
,請為 Capybara 測試定義一個基類,如下所示:
require 'capybara/dsl'
class CapybaraTestCase < Test :: Unit :: TestCase
include Capybara :: DSL
def teardown
Capybara . reset_sessions!
Capybara . use_default_driver
end
end
如果您正在使用 Rails 系統測試,請參閱其文件以取得選擇您想要使用的驅動程式的資訊。
如果您使用 Rails,但不使用 Rails 系統測試,請在test_helper.rb
檔案中新增以下程式碼,以使 Capybara 在從ActionDispatch::IntegrationTest
衍生的所有測試案例中可用:
require 'capybara/rails'
require 'capybara/minitest'
class ActionDispatch :: IntegrationTest
# Make the Capybara DSL available in all integration tests
include Capybara :: DSL
# Make `assert_*` methods behave like Minitest assertions
include Capybara :: Minitest :: Assertions
# Reset sessions and driver between tests
teardown do
Capybara . reset_sessions!
Capybara . use_default_driver
end
end
如果您不使用 Rails,請為 Capybara 測試定義一個基類,如下所示:
require 'capybara/minitest'
class CapybaraTestCase < Minitest :: Test
include Capybara :: DSL
include Capybara :: Minitest :: Assertions
def teardown
Capybara . reset_sessions!
Capybara . use_default_driver
end
end
請記住在任何覆蓋teardown
的子類別中呼叫super
。
若要切換驅動程序,請設定Capybara.current_driver
。例如,
class BlogTest < ActionDispatch :: IntegrationTest
setup do
Capybara . current_driver = Capybara . javascript_driver # :selenium by default
end
test 'shows blog posts' do
# ... this test is run with Selenium ...
end
end
依照上述 Minitest 說明進行操作,另外還需要 capybara/minitest/spec
page . must_have_content ( 'Important!' )
Capybara 使用相同的 DSL 來驅動各種瀏覽器和無頭驅動程式。
預設情況下,Capybara 使用:rack_test
驅動程序,該驅動程式速度快但有局限性:它不支援 JavaScript,也無法存取 Rack 應用程式外部的 HTTP 資源,例如遠端 API 和 OAuth 服務。要解決這些限制,您可以為您的功能設定不同的預設驅動程式。例如,如果您希望在 Selenium 中運行所有內容,您可以這樣做:
Capybara . default_driver = :selenium # :selenium_chrome and :selenium_chrome_headless are also registered
但是,如果您使用 RSpec 或 Cucumber (並且您的應用程式無需 JS 即可正常運行),您可能需要考慮將速度更快的:rack_test
保留為default_driver ,並僅使用js: true
標記那些需要支援JavaScript 的驅動程式的測試或@javascript
,分別。預設情況下,JavaScript 測試使用:selenium
驅動程式運行。您可以透過設定Capybara.javascript_driver
來更改此設定。
您也可以臨時變更驅動程式(通常在之前/設定和之後/拆卸區塊中):
Capybara . current_driver = :selenium # temporarily select different driver
# tests here
Capybara . use_default_driver # switch back to default driver
注意:切換驅動程式會建立一個新會話,因此您可能無法在測試中進行切換。
RackTest 是 Capybara 的預設驅動程式。它是用純 Ruby 寫的,不支援執行 JavaScript。由於 RackTest 驅動程式直接與 Rack 介面交互,因此不需要啟動伺服器。但是,這意味著如果您的應用程式不是 Rack 應用程式(Rails、Sinatra 和大多數其他 Ruby 框架都是 Rack 應用程式),那麼您無法使用此驅動程式。此外,您不能使用 RackTest 驅動程式來測試遠端應用程序,或存取您的應用程式可能與之互動的遠端 URL(例如,重定向到外部網站、外部 API 或 OAuth 服務)。
capybara-mechanize 提供了一個類似的驅動程序,可以存取遠端伺服器。
RackTest 可以配置一組標頭,如下所示:
Capybara . register_driver :rack_test do | app |
Capybara :: RackTest :: Driver . new ( app , headers : { 'HTTP_USER_AGENT' => 'Capybara' } )
end
請參閱有關新增和配置驅動程式的部分。
Capybara 支援 Selenium 3.5+ (Webdriver)。為了使用 Selenium,您需要安裝selenium-webdriver
gem,如果您使用捆綁器,請將其新增至您的 Gemfile 中。
Capybara 預先註冊了許多使用 Selenium 的命名驅動程式 - 它們是:
這些應該可以在本機桌面配置中使用(透過相關軟體安裝),但如果在 CI 環境中使用,您可能需要自訂它們,其中可能需要將其他選項傳遞到瀏覽器。請參閱有關新增和配置驅動程式的部分。
注意:在不同執行緒中執行伺服器的驅動程式可能不會與您的測試共用相同的事務,導致測試和測試伺服器之間無法共用數據,請參閱下方的事務和資料庫設定。
完整的參考可以在 rubydoc.info 上找到。
注意:預設情況下,Capybara 只會定位可見元素。這是因為真實使用者無法與不可見元素互動。
注意:Capybara 中的所有搜尋均區分大小寫。這是因為 Capybara 大量使用 XPath,而 XPath 不支援區分大小寫。
您可以使用訪問方法導航到其他頁面:
visit ( '/projects' )
visit ( post_comments_path ( post ) )
存取方法僅採用單一參數,請求方法始終為 GET。
您可以取得瀏覽工作階段的目前路徑,並使用have_current_path
匹配器進行測試:
expect ( page ) . to have_current_path ( post_comments_path ( post ) )
注意:您也可以透過直接測試current_path
的值來斷言目前路徑。但是,使用have_current_path
匹配器更安全,因為它使用 Capybara 的等待行為來確保前面的操作(例如click_link
)已完成。
完整參考:Capybara::Node::Actions
您可以透過以下連結和按鈕與網頁應用程式互動。 Capybara 會自動遵循任何重定向,並提交與按鈕關聯的表單。
click_link ( 'id-of-link' )
click_link ( 'Link Text' )
click_button ( 'Save' )
click_on ( 'Link Text' ) # clicks on either links or buttons
click_on ( 'Button Value' )
完整參考:Capybara::Node::Actions
有許多用於與表單元素互動的工具:
fill_in ( 'First Name' , with : 'John' )
fill_in ( 'Password' , with : 'Seekrit' )
fill_in ( 'Description' , with : 'Really Long Text...' )
choose ( 'A Radio Button' )
check ( 'A Checkbox' )
uncheck ( 'A Checkbox' )
attach_file ( 'Image' , '/path/to/image.jpg' )
select ( 'Option' , from : 'Select Box' )
完整參考:Capybara::Node::Matchers
Capybara 有一組豐富的選項,用於查詢頁面是否存在某些元素,以及使用和操作這些元素。
page . has_selector? ( 'table tr' )
page . has_selector? ( :xpath , './/table/tr' )
page . has_xpath? ( './/table/tr' )
page . has_css? ( 'table tr.foo' )
page . has_content? ( 'foo' )
注意:否定形式如has_no_selector?
與not has_selector?
。請閱讀有關非同步 JavaScript 的部分以取得解釋。
您可以將它們與 RSpec 的魔術匹配器一起使用:
expect ( page ) . to have_selector ( 'table tr' )
expect ( page ) . to have_selector ( :xpath , './/table/tr' )
expect ( page ) . to have_xpath ( './/table/tr' )
expect ( page ) . to have_css ( 'table tr.foo' )
expect ( page ) . to have_content ( 'foo' )
完整參考:Capybara::Node::Finders
您也可以找到特定元素,以便操作它們:
find_field ( 'First Name' ) . value
find_field ( id : 'my_field' ) . value
find_link ( 'Hello' , :visible => :all ) . visible?
find_link ( class : [ 'some_class' , 'some_other_class' ] , :visible => :all ) . visible?
find_button ( 'Send' ) . click
find_button ( value : '1234' ) . click
find ( :xpath , ".//table/tr" ) . click
find ( "#overlay" ) . find ( "h1" ) . click
all ( 'a' ) . each { | a | a [ :href ] }
如果您需要透過其他屬性/屬性來尋找元素,您還可以傳遞一個過濾器塊,該過濾器塊將在正常等待行為中進行檢查。如果您發現自己需要經常使用它,那麼最好添加自訂選擇器或為現有選擇器添加過濾器。
find_field ( 'First Name' ) { | el | el [ 'data-xyz' ] == '123' }
find ( "#img_loading" ) { | img | img [ 'complete' ] == true }
注意: find
將等待頁面上出現元素,如 Ajax 部分所述。如果該元素未出現,則會引發錯誤。
這些元素都具有所有可用的 Capybara DSL 方法,因此您可以將它們限製到頁面的特定部分:
find ( '#navigation' ) . click_link ( 'Home' )
expect ( find ( '#navigation' ) ) . to have_button ( 'Sign out' )
Capybara 可以將某些操作限制在頁面的特定區域內,例如與表單互動或點擊連結和按鈕。為此,您可以使用通用的inside方法。您可以選擇指定要使用的選擇器類型。
within ( "li#employee" ) do
fill_in 'Name' , with : 'Jimmy'
end
within ( :xpath , ".//li[@id='employee']" ) do
fill_in 'Name' , with : 'Jimmy'
end
有一些特殊方法可以將範圍限制為特定欄位集(由欄位集圖例標記的 id 或文字標識)以及特定表(由表標題標記的 id 或文字標識)。
within_fieldset ( 'Employee' ) do
fill_in 'Name' , with : 'Jimmy'
end
within_table ( 'Employee' ) do
fill_in 'Name' , with : 'Jimmy'
end
Capybara 提供了一些方法來輕鬆找到和切換視窗:
facebook_window = window_opened_by do
click_button 'Like'
end
within_window facebook_window do
find ( '#login_email' ) . set ( '[email protected]' )
find ( '#login_password' ) . set ( 'qwerty' )
click_button 'Submit'
end
在支援它的驅動程式中,您可以輕鬆執行 JavaScript:
page . execute_script ( "$('body').empty()" )
對於簡單的表達式,您可以傳回腳本的結果。
result = page . evaluate_script ( '4 + 4' ) ;
對於更複雜的腳本,您需要將它們編寫為一個表達式。
result = page . evaluate_script ( <<~JS , 3 , element )
(function(n, el){
var val = parseInt(el.value, 10);
return n+val;
})(arguments[0], arguments[1])
JS
在支援它的驅動程式中,您可以接受、忽略和回應警報、確認和提示。
您可以透過將產生警報的程式碼包裝在區塊中來接受警報訊息:
accept_alert 'optional text or regex' do
click_link ( 'Show Alert' )
end
您也可以將確認包裝在區塊中來接受或拒絕確認:
accept_confirm 'optional text' do
click_link ( 'Show Confirm' )
end
dismiss_confirm 'optional text' do
click_link ( 'Show Confirm' )
end
您也可以接受或忽略提示,也可以提供用於填寫回應的文字:
accept_prompt ( 'optional text' , with : 'Linus Torvalds' ) do
click_link ( 'Show Prompt About Linux' )
end
dismiss_prompt ( 'optional text' ) do
click_link ( 'Show Prompt About Linux' )
end
所有模態方法都會傳回所呈現的訊息。因此,您可以透過將返回值指派給變數來存取提示訊息:
message = accept_prompt ( with : 'Linus Torvalds' ) do
click_link ( 'Show Prompt About Linux' )
end
expect ( message ) . to eq ( 'Who is the chief architect of Linux?' )
拍攝當前頁面的快照並查看它可能會很有用:
save_and_open_page
您也可以使用page.html以字串形式檢索 DOM 的目前狀態。
print page . html
這對於調試來說非常有用。您應該避免針對page.html
的內容進行測試,而應使用更具表現力的查找器方法。
最後,在支援它的驅動程式中,您可以保存螢幕截圖:
page . save_screenshot ( 'screenshot.png' )
或讓它保存並自動打開:
save_and_open_screenshot
螢幕截圖儲存到Capybara.save_path
,相對於應用程式目錄。如果您需要capybara/rails
, Capybara.save_path
將預設為tmp/capybara
。
接受選擇器的幫助器和匹配器共享一個通用的方法簽名,其中包括:
這些參數通常以某種方式是可選的。
名稱參數決定要使用的選擇器。當助手明確傳遞選擇器名稱時,此參數是可選的(例如, find_field
使用:field
, find_link
使用:link
等):
page . html # => '<a href="/">Home</a>'
page . find ( :link ) == page . find_link
page . html # => '<input>'
page . find ( :field ) == page . find_field
定位器參數通常表示可以最有意義地區分與選擇器匹配的元素和不匹配選擇器的元素的資訊:
page . html # => '<div id="greeting">Hello world</div>'
page . find ( :css , 'div' ) . text # => 'Hello world'
page . find ( :xpath , './/div' ) . text # => 'Hello world'
當該方法可以從Capybara.default_selector
配置推斷預設值時,像find
和all
這樣的通用查找器方法可以接受定位器作為其第一個位置參數: