Capybara помогает вам тестировать веб-приложения, моделируя, как реальный пользователь будет взаимодействовать с вашим приложением. Он не зависит от драйвера, на котором выполняются ваши тесты, и поставляется со встроенной поддержкой Rack::Test и Selenium. WebKit поддерживается через внешний драгоценный камень.
Если вы и/или ваша компания цените 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-адресом (или находится по нему), вам потребуется использовать другой драйвер. Если вы используете Rails 5.0+, но не используете системные тесты Rails из версии 5.1, вы, вероятно, также захотите поменять «сервер», используемый для запуска вашего приложения, на Puma, чтобы соответствовать настройкам Rails по умолчанию.
Capybara . server = :puma # Until your setup is working
Capybara . server = :puma , { Silent : true } # To clean up your test output
Драгоценный камень cucumber-rails
поставляется со встроенной поддержкой 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
Вы можете переключиться на Capybara.javascript_driver
(по умолчанию :selenium
), пометив сценарии (или функции) с помощью @javascript
:
@javascript
Scenario : do something Ajaxy
When I click the Ajax link
...
Также существуют явные теги для каждого зарегистрированного драйвера, настроенного для вас ( @selenium
, @rack_test
и т. д.).
Загрузите поддержку RSpec 3.5+, добавив следующую строку (обычно в файл spec_helper.rb
):
require 'capybara/rspec'
Если вы используете Rails, поместите свои спецификации Capybara в spec/features
или spec/system
(работает только в том случае, если они настроены в RSpec), а если ваши спецификации Capybara находятся в другом каталоге, то пометьте группы примеров type: :feature
или type: :system
в зависимости от типа теста, который вы пишете.
Если вы используете системные спецификации Rails, ознакомьтесь с их документацией, чтобы выбрать драйвер, который вы хотите использовать.
Если вы не используете Rails, пометьте все группы примеров, в которых вы хотите использовать Capybara, 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», вы можете установить методы прокси, потребовав «capybara/rspec/matcher_proxies» после запроса RSpec и «capybara/dsl».
Если вы используете 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
Не забудьте вызвать super
во всех подклассах, которые переопределяют teardown
.
Чтобы переключить драйвер, установите 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 и не может получить доступ к ресурсам HTTP за пределами вашего приложения Rack, таким как удаленные API и службы OAuth. Чтобы обойти эти ограничения, вы можете настроить другой драйвер по умолчанию для своих функций. Например, если вы предпочитаете запускать все в Selenium, вы можете сделать:
Capybara . default_driver = :selenium # :selenium_chrome and :selenium_chrome_headless are also registered
Однако, если вы используете RSpec или Cucumber (и ваше приложение работает корректно без JS), вместо этого вы можете рассмотреть возможность оставить более быстрый :rack_test
в качестве default_driver и пометить только те тесты, для которых требуется драйвер с поддержкой JavaScript, используя js: true
или @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
и добавить его в свой Gemfile, если вы используете сборщик.
Capybara предварительно регистрирует ряд именованных драйверов, использующих Selenium:
Они должны работать (при установке соответствующего программного обеспечения) в конфигурации локального рабочего стола, но вам может потребоваться настроить их при использовании в среде CI, где в браузеры может потребоваться передать дополнительные параметры. См. раздел о добавлении и настройке драйверов.
Примечание . Драйверы, запускающие сервер в другом потоке, могут не использовать одну и ту же транзакцию с вашими тестами, в результате чего данные не будут совместно использоваться между вашим тестовым и тестовым серверами, см. раздел «Транзакции и настройка базы данных» ниже.
Полная ссылка доступна на Rubydoc.info .
Примечание. По умолчанию Capybara находит только видимые элементы. Это связано с тем, что реальный пользователь не сможет взаимодействовать с невидимыми элементами.
Примечание . Все поисковые запросы в Capybara чувствительны к регистру . Это связано с тем, что Capybara активно использует 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 позволяет ограничить определенные действия, такие как взаимодействие с формами или нажатие ссылок и кнопок, в пределах определенной области страницы. Для этой цели вы можете использовать общий метод внутри . При желании вы можете указать, какой тип селектора использовать.
within ( "li#employee" ) do
fill_in 'Name' , with : 'Jimmy'
end
within ( :xpath , ".//li[@id='employee']" ) do
fill_in 'Name' , with : 'Jimmy'
end
Существуют специальные методы для ограничения области определенным набором полей, идентифицируемым либо идентификатором, либо текстом тега легенды набора полей, а также конкретной таблицей, идентифицируемой либо идентификатором, либо текстом тега заголовка таблицы.
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
Вы также можете получить текущее состояние DOM в виде строки, используя page.html .
print page . html
Это в основном полезно для отладки. Вам следует избегать тестирования содержимого page.html
и вместо этого использовать более выразительные методы поиска.
Наконец, в драйверах, которые это поддерживают, можно сохранить скриншот:
page . save_screenshot ( 'screenshot.png' )
Или сохранить и автоматически открыть:
save_and_open_screenshot
Снимки экрана сохраняются в Capybara.save_path
относительно каталога приложения. Если вам требуется capybara/rails
, Capybara.save_path
по умолчанию будет иметь значение tmp/capybara
.
Помощники и средства сопоставления, которые принимают селекторы, имеют общую сигнатуру метода, которая включает в себя:
Эти аргументы обычно так или иначе не являются обязательными.
Аргумент name определяет используемый селектор. Аргумент является необязательным, если помощник явно передает имя селектора (например, 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'
Методы поиска общего назначения, такие как find
и all
, могут принимать локатор в качестве своего первого позиционного аргумента, когда метод может вывести значение по умолчанию из конфигурации Capybara.default_selector
: