Capivara ajuda você a testar aplicações web simulando como um usuário real interagiria com seu aplicativo. Ele é independente do driver que executa seus testes e vem com suporte integrado para Rack::Test e Selenium. O WebKit é suportado por meio de um gem externo.
Se você e/ou sua empresa encontram valor na Capivara e gostariam de contribuir financeiramente para sua manutenção e desenvolvimento contínuos, visite Patreon
Precisar de ajuda? Pergunte nas discussões (por favor, não abra um problema): https://github.com/orgs/teamcapybara/discussions/categories/qa
Capivara requer Ruby 3.0.0 ou posterior. Para instalar, adicione esta linha ao seu Gemfile
e execute bundle install
:
gem 'capybara'
Se a aplicação que você está testando for uma aplicação Rails, adicione esta linha ao seu arquivo auxiliar de teste:
require 'capybara/rails'
Se o aplicativo que você está testando for um aplicativo Rack, mas não Rails, defina Capybara.app como seu aplicativo Rack:
Capybara . app = MyRackApp
Se você precisar testar o JavaScript ou se seu aplicativo interagir com (ou estiver localizado em) um URL remoto, você precisará usar um driver diferente. Se estiver usando Rails 5.0+, mas não estiver usando os testes de sistema Rails da versão 5.1, você provavelmente também desejará trocar o "servidor" usado para iniciar seu aplicativo no Puma para corresponder aos padrões do Rails.
Capybara . server = :puma # Until your setup is working
Capybara . server = :puma , { Silent : true } # To clean up your test output
A gema cucumber-rails
vem com suporte para Capivara integrado. Se você não estiver usando Rails, carregue manualmente o módulo capybara/cucumber
:
require 'capybara/cucumber'
Capybara . app = MyRackApp
Você pode usar o DSL Capivara em suas etapas, assim:
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
Você pode mudar para Capybara.javascript_driver
( :selenium
por padrão) marcando cenários (ou recursos) com @javascript
:
@javascript
Scenario : do something Ajaxy
When I click the Ajax link
...
Existem também tags explícitas para cada driver registrado configuradas para você ( @selenium
, @rack_test
, etc).
Carregue o suporte do RSpec 3.5+ adicionando a seguinte linha (normalmente ao seu arquivo spec_helper.rb
):
require 'capybara/rspec'
Se você estiver usando Rails, coloque suas especificações do Capybara em spec/features
ou spec/system
(só funciona se você tiver configurado no RSpec) e se você tiver suas especificações do Capybara em um diretório diferente, marque os grupos de exemplo com type: :feature
ou type: :system
dependendo do tipo de teste que você está escrevendo.
Se você estiver usando especificações do sistema Rails, consulte a documentação para selecionar o driver que deseja usar.
Se você não estiver usando Rails, marque todos os grupos de exemplo nos quais deseja usar Capivara com type: :feature
.
Agora você pode escrever suas especificações assim:
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
Use js: true
para mudar para Capybara.javascript_driver
( :selenium
por padrão) ou forneça uma opção :driver
para mudar para um driver específico. Por exemplo:
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 também vem com uma DSL integrada para criar testes de aceitação descritivos:
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
é na verdade apenas um alias para describe ..., type: :feature
, background
é um alias para before
, scenario
para it
e given
/ given!
apelidos para let
/ let!
, respectivamente.
Finalmente, os matchers Capybara também são suportados nas especificações de visualização:
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
Nota: Quando você requer métodos proxy 'capybara/rspec' são instalados para contornar colisões de nomes entre métodos Capybara::DSL all
/ within
e os matchers RSpec integrados com nomes idênticos. Se você optar por não exigir 'capybara/rspec', poderá instalar os métodos de proxy exigindo 'capybara/rspec/matcher_proxies' após exigir RSpec e 'capybara/dsl'
Se você estiver usando Test::Unit
, defina uma classe base para seus testes Capybara assim:
require 'capybara/dsl'
class CapybaraTestCase < Test :: Unit :: TestCase
include Capybara :: DSL
def teardown
Capybara . reset_sessions!
Capybara . use_default_driver
end
end
Se você estiver usando testes de sistema Rails, consulte a documentação deles para obter informações sobre como selecionar o driver que deseja usar.
Se você estiver usando Rails, mas não usando testes de sistema Rails, adicione o seguinte código em seu arquivo test_helper.rb
para disponibilizar o Capybara em todos os casos de teste derivados de 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
Se você não estiver usando Rails, defina uma classe base para seus testes Capivara assim:
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
Lembre-se de chamar super
em qualquer subclasse que substitua teardown
.
Para trocar o driver, defina Capybara.current_driver
. Por exemplo,
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
Siga as instruções acima para o Minitest e também exija capivara/minitest/spec
page . must_have_content ( 'Important!' )
Capivara usa o mesmo DSL para controlar uma variedade de navegadores e drivers sem cabeça.
Por padrão, o Capybara usa o driver :rack_test
, que é rápido, mas limitado: ele não suporta JavaScript, nem é capaz de acessar recursos HTTP fora do seu aplicativo Rack, como APIs remotas e serviços OAuth. Para contornar essas limitações, você pode configurar um driver padrão diferente para seus recursos. Por exemplo, se preferir rodar tudo em Selenium, você poderia fazer:
Capybara . default_driver = :selenium # :selenium_chrome and :selenium_chrome_headless are also registered
No entanto, se você estiver usando RSpec ou Cucumber (e seu aplicativo for executado corretamente sem JS), você pode considerar deixar o :rack_test
mais rápido como o default_driver e marcar apenas os testes que exigem um driver compatível com JavaScript usando js: true
ou @javascript
, respectivamente. Por padrão, os testes de JavaScript são executados usando o driver :selenium
. Você pode alterar isso configurando Capybara.javascript_driver
.
Você também pode alterar o driver temporariamente (normalmente nos blocos Antes/configuração e Depois/desmontagem):
Capybara . current_driver = :selenium # temporarily select different driver
# tests here
Capybara . use_default_driver # switch back to default driver
Nota : a troca do driver cria uma nova sessão, então talvez você não consiga trocar no meio de um teste.
RackTest é o driver padrão do Capivara. Ele é escrito em Ruby puro e não possui suporte para execução de JavaScript. Como o driver RackTest interage diretamente com as interfaces do Rack, ele não requer a inicialização de um servidor. No entanto, isso significa que se o seu aplicativo não for um aplicativo Rack (Rails, Sinatra e a maioria dos outros frameworks Ruby são aplicativos Rack), você não poderá usar este driver. Além disso, você não pode usar o driver RackTest para testar um aplicativo remoto ou para acessar URLs remotos (por exemplo, redirecionamentos para sites externos, APIs externas ou serviços OAuth) com os quais seu aplicativo possa interagir.
capybara-mechanize fornece um driver semelhante que pode acessar servidores remotos.
RackTest pode ser configurado com um conjunto de cabeçalhos como este:
Capybara . register_driver :rack_test do | app |
Capybara :: RackTest :: Driver . new ( app , headers : { 'HTTP_USER_AGENT' => 'Capybara' } )
end
Consulte a seção sobre como adicionar e configurar drivers.
Capivara suporta Selenium 3.5+ (Webdriver). Para usar o Selenium, você precisará instalar a gem selenium-webdriver
e adicioná-la ao seu Gemfile se estiver usando o bundler.
A Capivara pré-regista uma série de drivers nomeados que utilizam Selenium - são eles:
Eles devem funcionar (com instalação de software relevante) em uma configuração de desktop local, mas pode ser necessário personalizá-los se forem usados em um ambiente de CI onde opções adicionais podem precisar ser passadas para os navegadores. Consulte a seção sobre como adicionar e configurar drivers.
Nota : drivers que executam o servidor em um thread diferente podem não compartilhar a mesma transação que seus testes, fazendo com que os dados não sejam compartilhados entre seu teste e o servidor de teste, consulte Transações e configuração do banco de dados abaixo.
Uma referência completa está disponível em rubydoc.info .
Nota: Por padrão, o Capivara localizará apenas elementos visíveis. Isso ocorre porque um usuário real não seria capaz de interagir com elementos não visíveis.
Nota : Todas as pesquisas em Capivara diferenciam maiúsculas de minúsculas . Isso ocorre porque o Capivara usa muito o XPath, que não oferece suporte à insensibilidade a maiúsculas e minúsculas.
Você pode usar o método de visita para navegar para outras páginas:
visit ( '/projects' )
visit ( post_comments_path ( post ) )
O método visit leva apenas um único parâmetro, o método request é sempre GET.
Você pode obter o caminho atual da sessão de navegação e testá-lo usando o matcher have_current_path
:
expect ( page ) . to have_current_path ( post_comments_path ( post ) )
Nota : Você também pode afirmar o caminho atual testando o valor de current_path
diretamente. No entanto, usar o matcher have_current_path
é mais seguro, pois usa o comportamento de espera do Capybara para garantir que as ações anteriores (como click_link
) foram concluídas.
Referência completa: Capivara::Node::Actions
Você pode interagir com o webapp seguindo links e botões. Capivara segue automaticamente qualquer redirecionamento e envia formulários associados a botões.
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' )
Referência completa: Capivara::Node::Actions
Existem várias ferramentas para interagir com elementos de formulário:
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' )
Referência completa: Capivara::Node::Matchers
Capivara possui um rico conjunto de opções para consultar a página quanto à existência de determinados elementos e trabalhar e manipular esses elementos.
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' )
Nota: Os formulários negativos como has_no_selector?
são diferentes de not has_selector?
. Leia a seção sobre JavaScript assíncrono para obter uma explicação.
Você pode usá-los com os magic matchers do 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' )
Referência completa: Capivara::Node::Finders
Você também pode encontrar elementos específicos para manipulá-los:
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 ] }
Se você precisar encontrar elementos por atributos/propriedades adicionais, você também pode passar um bloco de filtro, que será verificado dentro do comportamento normal de espera. Se você precisar usar muito isso, talvez seja melhor adicionar um seletor personalizado ou adicionar um filtro a um seletor existente.
find_field ( 'First Name' ) { | el | el [ 'data-xyz' ] == '123' }
find ( "#img_loading" ) { | img | img [ 'complete' ] == true }
Nota : find
irá esperar que um elemento apareça na página, conforme explicado na seção Ajax. Se o elemento não aparecer, ocorrerá um erro.
Todos esses elementos possuem todos os métodos Capybara DSL disponíveis, então você pode restringi-los a partes específicas da página:
find ( '#navigation' ) . click_link ( 'Home' )
expect ( find ( '#navigation' ) ) . to have_button ( 'Sign out' )
A Capivara permite restringir determinadas ações, como interagir com formulários ou clicar em links e botões, a uma área específica da página. Para este propósito, você pode usar o método genérico dentro . Opcionalmente, você pode especificar que tipo de seletor usar.
within ( "li#employee" ) do
fill_in 'Name' , with : 'Jimmy'
end
within ( :xpath , ".//li[@id='employee']" ) do
fill_in 'Name' , with : 'Jimmy'
end
Existem métodos especiais para restringir o escopo a um conjunto de campos específico, identificado por um id ou pelo texto da tag de legenda do conjunto de campos, e a uma tabela específica, identificada por um id ou texto da tag de legenda da tabela.
within_fieldset ( 'Employee' ) do
fill_in 'Name' , with : 'Jimmy'
end
within_table ( 'Employee' ) do
fill_in 'Name' , with : 'Jimmy'
end
Capivara fornece alguns métodos para facilitar a localização e troca de janelas:
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
Nos drivers que o suportam, você pode executar JavaScript facilmente:
page . execute_script ( "$('body').empty()" )
Para expressões simples, você pode retornar o resultado do script.
result = page . evaluate_script ( '4 + 4' ) ;
Para scripts mais complicados você precisará escrevê-los como uma expressão.
result = page . evaluate_script ( <<~JS , 3 , element )
(function(n, el){
var val = parseInt(el.value, 10);
return n+val;
})(arguments[0], arguments[1])
JS
Nos drivers que o suportam, você pode aceitar, dispensar e responder a alertas, confirmações e solicitações.
Você pode aceitar mensagens de alerta agrupando o código que produz um alerta em um bloco:
accept_alert 'optional text or regex' do
click_link ( 'Show Alert' )
end
Você também pode aceitar ou descartar uma confirmação agrupando-a em um bloco:
accept_confirm 'optional text' do
click_link ( 'Show Confirm' )
end
dismiss_confirm 'optional text' do
click_link ( 'Show Confirm' )
end
Você também pode aceitar ou descartar solicitações e também fornecer texto para preencher na resposta:
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
Todos os métodos modais retornam a mensagem que foi apresentada. Assim, você pode acessar a mensagem de prompt atribuindo o retorno a uma variável:
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?' )
Pode ser útil tirar um instantâneo da página como ela está e dar uma olhada nela:
save_and_open_page
Você também pode recuperar o estado atual do DOM como uma string usando page.html .
print page . html
Isso é útil principalmente para depuração. Você deve evitar testar o conteúdo de page.html
e, em vez disso, usar métodos de localização mais expressivos.
Finalmente, nos drivers que o suportam, você pode salvar uma captura de tela:
page . save_screenshot ( 'screenshot.png' )
Ou salve-o e abra-o automaticamente:
save_and_open_screenshot
As capturas de tela são salvas em Capybara.save_path
, relativo ao diretório do aplicativo. Se você exigiu capybara/rails
, Capybara.save_path
será padronizado como tmp/capybara
.
Helpers e matchers que aceitam seletores compartilham uma assinatura de método comum que inclui:
Esses argumentos geralmente são opcionais de uma forma ou de outra.
O argumento name determina o seletor a ser usado. O argumento é opcional quando um auxiliar transmite explicitamente o nome do seletor (por exemplo, find_field
usa :field
, find_link
usa :link
, etc):
page . html # => '<a href="/">Home</a>'
page . find ( :link ) == page . find_link
page . html # => '<input>'
page . find ( :field ) == page . find_field
O argumento locator geralmente representa informações que podem distinguir de forma mais significativa um elemento que corresponde ao seletor de um elemento que não corresponde:
page . html # => '<div id="greeting">Hello world</div>'
page . find ( :css , 'div' ) . text # => 'Hello world'
page . find ( :xpath , './/div' ) . text # => 'Hello world'
Métodos de localização de uso geral, como find
e all
podem aceitar o localizador como seu primeiro argumento posicional quando o método pode inferir o valor padrão da configuração Capybara.default_selector
: