Capybara vous aide à tester des applications Web en simulant la manière dont un utilisateur réel interagirait avec votre application. Il est indépendant du pilote qui exécute vos tests et est livré avec la prise en charge intégrée de Rack::Test et Selenium. WebKit est pris en charge via une gemme externe.
Si vous et/ou votre entreprise trouvez de la valeur à Capybara et souhaitez contribuer financièrement à sa maintenance et à son développement continus, veuillez visiter Patreon.
Besoin d'aide ? Posez des questions sur les discussions (veuillez ne pas ouvrir de problème) : https://github.com/orgs/teamcapybara/discussions/categories/qa
Capybara nécessite Ruby 3.0.0 ou version ultérieure. Pour installer, ajoutez cette ligne à votre Gemfile
et exécutez bundle install
:
gem 'capybara'
Si l'application que vous testez est une application Rails, ajoutez cette ligne à votre fichier d'aide au test :
require 'capybara/rails'
Si l'application que vous testez est une application Rack, mais pas Rails, définissez Capybara.app sur votre application Rack :
Capybara . app = MyRackApp
Si vous devez tester JavaScript ou si votre application interagit avec (ou se trouve sur) une URL distante, vous devrez utiliser un autre pilote. Si vous utilisez Rails 5.0+, mais n'utilisez pas les tests du système Rails à partir de 5.1, vous souhaiterez probablement également échanger le "serveur" utilisé pour lancer votre application vers Puma afin de correspondre aux valeurs par défaut de Rails.
Capybara . server = :puma # Until your setup is working
Capybara . server = :puma , { Silent : true } # To clean up your test output
Le joyau cucumber-rails
est livré avec le support Capybara intégré. Si vous n'utilisez pas Rails, chargez manuellement le module capybara/cucumber
:
require 'capybara/cucumber'
Capybara . app = MyRackApp
Vous pouvez utiliser le Capybara DSL dans vos démarches, comme ceci :
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
Vous pouvez passer au Capybara.javascript_driver
( :selenium
par défaut) en marquant des scénarios (ou fonctionnalités) avec @javascript
:
@javascript
Scenario : do something Ajaxy
When I click the Ajax link
...
Il existe également des balises explicites pour chaque pilote enregistré configuré pour vous ( @selenium
, @rack_test
, etc.).
Chargez la prise en charge de RSpec 3.5+ en ajoutant la ligne suivante (généralement à votre fichier spec_helper.rb
) :
require 'capybara/rspec'
Si vous utilisez Rails, placez vos spécifications Capybara dans spec/features
ou spec/system
(ne fonctionne que si vous l'avez configuré dans RSpec) et si vous avez vos spécifications Capybara dans un répertoire différent, marquez les groupes d'exemples avec type: :feature
ou type: :system
selon le type de test que vous écrivez.
Si vous utilisez les spécifications du système Rails, veuillez consulter leur documentation pour sélectionner le pilote que vous souhaitez utiliser.
Si vous n'utilisez pas Rails, marquez tous les groupes d'exemples dans lesquels vous souhaitez utiliser Capybara avec type: :feature
.
Vous pouvez maintenant écrire vos spécifications comme ceci :
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
Utilisez js: true
pour passer au Capybara.javascript_driver
( :selenium
par défaut), ou fournissez une option :driver
pour passer à un pilote spécifique. Par exemple:
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 est également livré avec un DSL intégré pour créer des tests d'acceptation descriptifs :
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
n'est en fait qu'un alias pour describe ..., type: :feature
, background
est un alias pour before
, it
scenario
et given
/ given!
alias pour let
/ let!
, respectivement.
Enfin, les matchers Capybara sont également pris en charge dans les spécifications d'affichage :
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
Remarque : Lorsque vous avez besoin d'installer des méthodes proxy 'capybara/rspec' pour contourner les collisions de noms entre les méthodes Capybara::DSL all
/ within
et les matchers RSpec intégrés portant le même nom. Si vous choisissez de ne pas exiger « capybara/rspec », vous pouvez installer les méthodes proxy en exigeant « capybara/rspec/matcher_proxies » après avoir requis RSpec et « capybara/dsl ».
Si vous utilisez Test::Unit
, définissez une classe de base pour vos tests Capybara comme ceci :
require 'capybara/dsl'
class CapybaraTestCase < Test :: Unit :: TestCase
include Capybara :: DSL
def teardown
Capybara . reset_sessions!
Capybara . use_default_driver
end
end
Si vous utilisez les tests du système Rails, veuillez consulter leur documentation pour obtenir des informations sur la sélection du pilote que vous souhaitez utiliser.
Si vous utilisez Rails, mais pas les tests système Rails, ajoutez le code suivant dans votre fichier test_helper.rb
pour rendre Capybara disponible dans tous les cas de test dérivés d' 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
Si vous n'utilisez pas Rails, définissez une classe de base pour vos tests Capybara comme ceci :
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
N'oubliez pas d'appeler super
dans toutes les sous-classes qui remplacent teardown
.
Pour changer de pilote, définissez Capybara.current_driver
. Par exemple,
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
Suivez les instructions ci-dessus pour Minitest et exigez en plus capybara/minitest/spec
page . must_have_content ( 'Important!' )
Capybara utilise le même DSL pour piloter une variété de pilotes de navigateur et sans tête.
Par défaut, Capybara utilise le pilote :rack_test
, qui est rapide mais limité : il ne prend pas en charge JavaScript et n'est pas non plus capable d'accéder aux ressources HTTP en dehors de votre application Rack, telles que les API distantes et les services OAuth. Pour contourner ces limitations, vous pouvez configurer un pilote par défaut différent pour vos fonctionnalités. Par exemple, si vous préférez tout exécuter dans Selenium, vous pouvez faire :
Capybara . default_driver = :selenium # :selenium_chrome and :selenium_chrome_headless are also registered
Cependant, si vous utilisez RSpec ou Cucumber (et que votre application fonctionne correctement sans JS), vous pouvez plutôt envisager de laisser le plus rapide :rack_test
comme default_driver et de marquer uniquement les tests qui nécessitent un pilote compatible JavaScript utilisant js: true
ou @javascript
, respectivement. Par défaut, les tests JavaScript sont exécutés à l'aide du pilote :selenium
. Vous pouvez modifier cela en définissant Capybara.javascript_driver
.
Vous pouvez également modifier temporairement le pilote (généralement dans les blocs Avant/installation et Après/démontage) :
Capybara . current_driver = :selenium # temporarily select different driver
# tests here
Capybara . use_default_driver # switch back to default driver
Remarque : changer de pilote crée une nouvelle session, vous ne pourrez donc peut-être pas changer en cours de test.
RackTest est le pilote par défaut de Capybara. Il est écrit en Ruby pur et ne prend pas en charge l'exécution de JavaScript. Étant donné que le pilote RackTest interagit directement avec les interfaces Rack, il ne nécessite pas de démarrage de serveur. Cependant, cela signifie que si votre application n'est pas une application Rack (Rails, Sinatra et la plupart des autres frameworks Ruby sont des applications Rack), vous ne pouvez pas utiliser ce pilote. De plus, vous ne pouvez pas utiliser le pilote RackTest pour tester une application distante ou pour accéder à des URL distantes (par exemple, des redirections vers des sites externes, des API externes ou des services OAuth) avec lesquelles votre application pourrait interagir.
capybara-mechanize fournit un pilote similaire qui peut accéder aux serveurs distants.
RackTest peut être configuré avec un ensemble d'en-têtes comme celui-ci :
Capybara . register_driver :rack_test do | app |
Capybara :: RackTest :: Driver . new ( app , headers : { 'HTTP_USER_AGENT' => 'Capybara' } )
end
Voir la section sur l'ajout et la configuration des pilotes.
Capybara prend en charge Selenium 3.5+ (Webdriver). Pour utiliser Selenium, vous devrez installer le gem selenium-webdriver
et l'ajouter à votre Gemfile si vous utilisez un bundler.
Capybara pré-enregistre un certain nombre de pilotes nommés qui utilisent Selenium :
Ceux-ci devraient fonctionner (avec l'installation du logiciel approprié) dans une configuration de bureau local, mais vous devrez peut-être les personnaliser si vous les utilisez dans un environnement CI où des options supplémentaires peuvent devoir être transmises aux navigateurs. Voir la section sur l'ajout et la configuration des pilotes.
Remarque : les pilotes qui exécutent le serveur dans un thread différent peuvent ne pas partager la même transaction que vos tests, ce qui empêche le partage des données entre votre test et le serveur de test, voir Transactions et configuration de la base de données ci-dessous.
Une référence complète est disponible sur rubydoc.info .
Remarque : Par défaut, Capybara localisera uniquement les éléments visibles. En effet, un utilisateur réel ne pourrait pas interagir avec des éléments non visibles.
Remarque : Toutes les recherches dans Capybara sont sensibles à la casse . En effet, Capybara utilise beaucoup XPath, qui ne prend pas en charge l'insensibilité à la casse.
Vous pouvez utiliser la méthode de visite pour accéder à d'autres pages :
visit ( '/projects' )
visit ( post_comments_path ( post ) )
La méthode de visite ne prend qu'un seul paramètre, la méthode de requête est toujours GET.
Vous pouvez obtenir le chemin actuel de la session de navigation et le tester à l'aide du matcher have_current_path
:
expect ( page ) . to have_current_path ( post_comments_path ( post ) )
Remarque : Vous pouvez également affirmer le chemin actuel en testant directement la valeur de current_path
. Cependant, l'utilisation du matcher have_current_path
est plus sûre car elle utilise le comportement d'attente de Capybara pour garantir que les actions précédentes (telles qu'un click_link
) sont terminées.
Référence complète : Capybara :: Node :: Actions
Vous pouvez interagir avec la webapp en suivant les liens et les boutons. Capybara suit automatiquement toutes les redirections et soumet des formulaires associés aux boutons.
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' )
Référence complète : Capybara :: Node :: Actions
Il existe un certain nombre d'outils pour interagir avec les éléments de formulaire :
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' )
Référence complète : Capybara :: Node :: Matchers
Capybara dispose d'un riche ensemble d'options pour interroger la page sur l'existence de certains éléments, ainsi que pour travailler avec et manipuler ces éléments.
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' )
Remarque : Les formes négatives comme has_no_selector?
sont différents de not has_selector?
. Lisez la section sur JavaScript asynchrone pour une explication.
Vous pouvez les utiliser avec les magic matchers de 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' )
Référence complète : Capybara :: Node :: Finders
Vous pouvez également retrouver des éléments spécifiques, afin de les manipuler :
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 ] }
Si vous avez besoin de rechercher des éléments par attributs/propriétés supplémentaires, vous pouvez également transmettre un bloc de filtre, qui sera vérifié dans le comportement d'attente normal. Si vous avez souvent besoin de l'utiliser, vous feriez peut-être mieux d'ajouter un sélecteur personnalisé ou d'ajouter un filtre à un sélecteur existant.
find_field ( 'First Name' ) { | el | el [ 'data-xyz' ] == '123' }
find ( "#img_loading" ) { | img | img [ 'complete' ] == true }
Remarque : find
attendra qu'un élément apparaisse sur la page, comme expliqué dans la section Ajax. Si l'élément n'apparaît pas, cela générera une erreur.
Ces éléments disposent tous de toutes les méthodes Capybara DSL disponibles, vous pouvez donc les restreindre à des parties spécifiques de la page :
find ( '#navigation' ) . click_link ( 'Home' )
expect ( find ( '#navigation' ) ) . to have_button ( 'Sign out' )
Capybara permet de restreindre certaines actions, comme interagir avec des formulaires ou cliquer sur des liens et des boutons, à une zone spécifique de la page. Pour cela, vous pouvez utiliser la méthode générique inside . Vous pouvez éventuellement spécifier le type de sélecteur à utiliser.
within ( "li#employee" ) do
fill_in 'Name' , with : 'Jimmy'
end
within ( :xpath , ".//li[@id='employee']" ) do
fill_in 'Name' , with : 'Jimmy'
end
Il existe des méthodes spéciales pour restreindre la portée à un ensemble de champs spécifique, identifié par un identifiant ou le texte de la balise de légende de l'ensemble de champs, et à une table spécifique, identifiée par un identifiant ou le texte de la balise de légende de la table.
within_fieldset ( 'Employee' ) do
fill_in 'Name' , with : 'Jimmy'
end
within_table ( 'Employee' ) do
fill_in 'Name' , with : 'Jimmy'
end
Capybara propose quelques méthodes pour faciliter la recherche et le changement de fenêtre :
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
Dans les pilotes qui le supportent, vous pouvez facilement exécuter JavaScript :
page . execute_script ( "$('body').empty()" )
Pour les expressions simples, vous pouvez renvoyer le résultat du script.
result = page . evaluate_script ( '4 + 4' ) ;
Pour les scripts plus compliqués, vous devrez les écrire sous la forme d'une seule expression.
result = page . evaluate_script ( <<~JS , 3 , element )
(function(n, el){
var val = parseInt(el.value, 10);
return n+val;
})(arguments[0], arguments[1])
JS
Dans les pilotes qui le prennent en charge, vous pouvez accepter, rejeter et répondre aux alertes, confirmations et invites.
Vous pouvez accepter les messages d'alerte en encapsulant le code qui produit une alerte dans un bloc :
accept_alert 'optional text or regex' do
click_link ( 'Show Alert' )
end
Vous pouvez également accepter ou rejeter une confirmation en l'enveloppant dans un bloc :
accept_confirm 'optional text' do
click_link ( 'Show Confirm' )
end
dismiss_confirm 'optional text' do
click_link ( 'Show Confirm' )
end
Vous pouvez également accepter ou rejeter les invites, et également fournir du texte à remplir pour la réponse :
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
Toutes les méthodes modales renvoient le message présenté. Ainsi, vous pouvez accéder au message d'invite en attribuant le retour à une variable :
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?' )
Il peut être utile de prendre un instantané de la page telle qu'elle est actuellement et d'y jeter un œil :
save_and_open_page
Vous pouvez également récupérer l'état actuel du DOM sous forme de chaîne en utilisant page.html .
print page . html
Ceci est surtout utile pour le débogage. Vous devez éviter de tester le contenu de page.html
et utiliser plutôt les méthodes de recherche plus expressives.
Enfin, dans les pilotes qui le supportent, vous pouvez enregistrer une capture d'écran :
page . save_screenshot ( 'screenshot.png' )
Ou faites-le enregistrer et ouvrir automatiquement :
save_and_open_screenshot
Les captures d'écran sont enregistrées dans Capybara.save_path
, par rapport au répertoire de l'application. Si vous avez requis capybara/rails
, Capybara.save_path
sera par défaut tmp/capybara
.
Les assistants et les matchers qui acceptent les sélecteurs partagent une signature de méthode commune qui comprend :
Ces arguments sont généralement facultatifs d’une manière ou d’une autre.
L'argument name détermine le sélecteur à utiliser. L'argument est facultatif lorsqu'un assistant transmet explicitement le nom du sélecteur (par exemple, find_field
utilise :field
, find_link
utilise :link
, etc.) :
page . html # => '<a href="/">Home</a>'
page . find ( :link ) == page . find_link
page . html # => '<input>'
page . find ( :field ) == page . find_field
L'argument locator représente généralement les informations permettant de distinguer de manière plus significative un élément qui correspond au sélecteur d'un élément qui ne le fait pas :
page . html # => '<div id="greeting">Hello world</div>'
page . find ( :css , 'div' ) . text # => 'Hello world'
page . find ( :xpath , './/div' ) . text # => 'Hello world'
Les méthodes de recherche à usage général comme find
et all
peuvent accepter le localisateur comme premier argument de position lorsque la méthode peut déduire la valeur par défaut de la configuration Capybara.default_selector
: