LoginSignup
1775
1772

More than 1 year has passed since last update.

使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」

Last updated at Posted at 2015-01-01

はじめに



使RSpec使RSpec4

Capybara使
Capybara使


13












便


Capybara使
Qiita使

使
view
使

使



RSpec

Capybara



Rails 4.2

Ruby 2.2

rspec-rails 3.1

Capybara 2.4

Poltergeist 1.5.1

2021-9-1


feature specsystem specCapybara使

13


1RSpec便RSpec
2使使使
3mock使使

123


使RSpec1RSpec便

使RSpec2使使

使RSpec3mock使




feature spec
E2E


require 'rails_helper'

RSpec.feature 'ログインとログアウト' do
  background do
    # ユーザを作成する
    User.create!(email: 'foo@example.com', password: '123456')
  end
  scenario 'ログインする' do
    # トップページを開く
    visit root_path
    # ログインフォームにEmailとパスワードを入力する
    fill_in 'Email', with: 'foo@example.com'
    fill_in 'Password', with: '123456'
    # ログインボタンをクリックする
    click_on 'ログイン'
    # ログインに成功したことを検証する
    expect(page).to have_content 'ログインしました'
  end
end

フィーチャスペックのエイリアス


 describe  itfeature  scenario 使

使


describe <=> feature

it <=> scenario

let <=> given

let! <=> given!

before <=> background


context  after 使

describe  it使
require 'rails_helper'

RSpec.describe 'ログインとログアウト', type: :feature do
  before do
    # ユーザを作成する
    User.create!(email: 'foo@example.com', password: '123456')
  end
  it 'ログインする' do
    # トップページを開く
    visit root_path
    # ログインフォームにEmailとパスワードを入力する
    fill_in 'Email', with: 'foo@example.com'
    fill_in 'Password', with: '123456'
    # ログインボタンをクリックする
    click_on 'ログイン'
    # ログインに成功したことを検証する
    expect(page).to have_content 'ログインしました'
  end
end

フィーチャスペックのセットアップ


Rails rspec-rails  Capybara gem




RSpec 3()

Capybara使


visit + path 
visit root_path
visit new_user_path

現在のページを再読み込み(リロード)する

Capybaraの標準APIにはリロード用のメソッドが無いので、「現在のパスに再度移動する」という操作でリロードをシミュレートします。

visit current_path

ボタンをクリックする

「ボタン」というのはsubmitボタンやbuttonタグを指します。

<input type="submit" name="commit" value="Save">
<!-- または -->
<!-- <button>Save</button> -->
click_button 'Save'

リンクをクリックする

CSSによって見た目がボタンっぽくなっていても、HTML上はa要素になっている場合は「リンク」と見なされるので注意が必要です。

<a href="/users/new">New User</a>
click_link 'New User'

リンクまたはボタンをクリックする

クリックする要素がリンクなのかボタンなのか、いちいち考えたくない場合は click_on が便利です。

<a href="/users/new">New User</a>
<input type="submit" name="commit" value="Save">
click_on 'New User'
click_on 'Save'

画像のalt属性を利用してリンクをクリックする

<a href="/users/1">
  <img alt="Alice" src="./profile.jpg">
</a>

<!-- buttonの場合はNG -->
<!-- <button> -->
<!--   <img alt="Alice" src="./profile.jpg"> -->
<!-- </button> -->
click_on 'Alice'
# または
# click_link 'Alice'

テキストボックスまたはテキストエリアに文字を入力する

<label for="blog_title">タイトル</label>
<input type="text" value="" name="blog[title]" id="blog_title">
fill_in 'タイトル', with: 'あけましておめでとうございます。'

セレクトボックスを選択する

<label for="japanese_calendar">和暦</label>
<select name="japanese_calendar" id="japanese_calendar">
  <option value="0">明治</option>
  <option value="1">大正</option>
  <option value="2">昭和</option>
  <option value="3">平成</option>
</select>
select '平成', from: '和暦'

チェックボックスのチェックをON/OFFする

<label for="mailmagazine">
    <input type="checkbox" name="mailmagazine" id="mailmagazine" value="1">
    メールマガジンを購読する
</label>
check 'メールマガジンを購読する'
uncheck 'メールマガジンを購読する'

ラジオボタンを選択する

<label>
  <input id="user_sex_male" name="user[sex]" type="radio" value="male" checked="checked">
  男性
</label>
<label>
  <input id="user_sex_female" name="user[sex]" type="radio" value="female">
  女性
</label>
choose '女性'

ファイルを添付する

"#{Rails.root}/spec/factories/profile_image.jpg" の部分は実際にファイル配置しているパスを指定してください。

attach_file 'プロフィール画像', "#{Rails.root}/spec/factories/profile_image.jpg"

hiddenに値をセットする

<input type="hidden" name="secret_value" id="secret_value">

find を普通に使うと画面に表示されている要素しか検索しないので、 visible: false オプションを付けます。

find('#secret_value', visible: false).set('secret!!')

ラベルがないフィールドを操作する

ラベルの代わりにid、name、placeholderを指定できます。

テキストボックスの場合

<input type="text" name="blog[title]" id="blog_title" value="" placeholder="ここにタイトルを入力します">
fill_in 'blog_title', with: 'あけましておめでとうございます。'
# または
# fill_in 'blog[title]', with: 'あけましておめでとうございます。'
# fill_in 'ここにタイトルを入力します', with: 'あけましておめでとうございます。'

セレクトボックスの場合

<select name="japanese_calendar" id="japanese_calendar">
  <option value="0">明治</option>
  <option value="1">大正</option>
  <option value="2">昭和</option>
  <option value="3">平成</option>
</select>
select '平成', from: 'japanese_calendar'

チェックボックスの場合

<input type="checkbox" name="mailmagazine" id="mailmagazine" value="1">
check 'mailmagazine'

FAQ「ラベルはあるのにラベル名を指定できません😣」

本当はこんなテストコードを書きたいのに・・・

fill_in '本文', with: '今日はいい天気'

「そんなフィールドは見つからない(Capybara::ElementNotFound: Unable to find field "本文" that is not disabled)」と怒られるので、泣く泣くこう書いてます😭

fill_in 'blog[content]', with: '今日はいい天気'

っていう人をよく見かけます。

そういう人はChromeのデベロッパーツールなどでHTMLを確認してください。
もしかするとこんなふうになってませんか?

<label>本文</label>
<input type="text" name="blog[content]" id="blog_content">

Capybaraでラベル名で選択できるようにするためにはlabelタグのfor属性を正しく設定(inputタグのid属性を指定)する必要があります。
具体的にはこうなってる必要があります。

<label for="blog_contet">本文</label>
<input type="text" name="blog[content]" id="blog_content">

シンプルなRailsアプリケーションであればViewを以下のように書けば自動的にlabelに適切なid属性が付くはずです。

<%= form_with(model: blog) do |f| %>
  <%= f.label :content %>
  <%= f.text_field :content %>
<% end %>

Vue.jsやReactでフォームを作っている場合でも考え方は同じでfor属性が適切に設定されていればOKなので、タグの構造を見直してみましょう。

画面やフォームの検証

ページ内に特定の文字列が表示されていることを検証する

<div class="alert alert-success">
  ユーザーが作成されました。
</div>
expect(page).to have_content 'ユーザーが作成されました。'

特定のタグやCSS要素に特定の文字列が表示されていることを検証する

<h1 class="information" id="information">大事なお知らせ</h1>
expect(page).to have_selector 'h1', text: '大事なお知らせ'

要素ではなく、CSSクラスやIDを使うこともできます。

expect(page).to have_selector '.information', text: '大事なお知らせ'
# または
expect(page).to have_selector '#information', text: '大事なお知らせ'
# 要素とクラスを組み合わせるのも可
expect(page).to have_selector 'h1.information', text: '大事なお知らせ'

要素の属性も指定することができます。

<a href="contacts/1" data-method="delete">delete</a>
expect(page).to have_selector 'a[data-method=delete]', text: 'delete'

text には正規表現を渡すこともできます。

expect(page).to have_selector 'h1', text: /^大事なお知らせ$/

ページ内に特定のボタンが表示されていることを検証する

<input type="submit" name="commit" value="Save">
expect(page).to have_button 'Save'

ページ内に特定のリンクが表示されていることを検証する

<a href="/users/sign_up">会員登録はこちら</a>
expect(page).to have_link '会員登録はこちら'

ページ内に特定のCSS要素が表示されていることを検証する

<!-- バリデーションエラー時のHTML -->
<div class="field_with_errors">
  <input type="text" value="" name="blog[title]" id="blog_title">
</div>
# ブログの新規作成画面を開く
visit new_blog_path
# 何も入力せずに作成ボタンをクリックする
click_on 'Create Blog'
# フォーム内の要素にfield_with_errorsクラスが付いていることを検証する
expect(page).to have_css '.field_with_errors'

テキストボックスに特定の値が入っていることを検証する

<!-- ブログの編集画面を開いたときのHTML -->
<label for="blog_title">タイトル</label>
<input type="text" value="あけましておめでとうございます。" name="blog[title]" id="blog_title">
# ブログの編集画面を開く
click_link 'Edit'
# 編集前のタイトルが表示されていることを検証する
expect(page).to have_field 'タイトル', with: 'あけましておめでとうございます。'

チェックボックスがチェックされていること/いないことを検証する

<label>
    <input type="checkbox" name="mailmagazine" id="mailmagazine" value="yes" checked="checked">
    メールマガジンを購読する
</label>
expect(page).to have_checked_field('メールマガジンを購読する')

チェックされて いないこと を検証する場合は have_unchecked_field を使います。

expect(page).to have_unchecked_field('メールマガジンを購読する')

チェックボックスが表示されていることを検証する(チェックの有無は無視する)

チェックボックスが表示されていることだけを検証したい、チェックの有無は気にしない、という場合は have_field を使います。

<label>
    <input type="checkbox" name="mailmagazine" id="mailmagazine" value="yes" checked="checked">
    メールマガジンを購読する
</label>
# チェックが付いていてもいなくてもパスする 
expect(page).to have_field('メールマガジンを購読する')

セレクトボックスで特定の項目が選択されていることを検証する

<label for="japanese_calendar">和暦</label>
<select name="japanese_calendar" id="japanese_calendar">
  <option value="明治">明治</option>
  <option value="大正">大正</option>
  <option selected="selected" value="昭和">昭和</option>
  <option value="平成">平成</option>
</select>
expect(page).to have_select('和暦', selected: '昭和')

セレクトボックスで特定の項目が存在することを検証する

<label for="japanese_calendar">和暦</label>
<select name="japanese_calendar" id="japanese_calendar">
  <option value="明治">明治</option>
  <option value="大正">大正</option>
  <option value="昭和">昭和</option>
  <option value="平成">平成</option>
</select>
expect(page).to have_select('和暦', options: ['明治', '大正', '昭和', '平成'])

selectedと一緒に検証することもできます。

expect(page).to have_select('和暦', selected: '昭和', options: ['明治', '大正', '昭和', '平成'])

この検証方法はこちらの記事で実際の使用例を見ることができます。

(応用) セレクトボックスでselectedになっている項目がないことを検証する

以下のように selected になっている項目がないセレクトボックスを想定します。

<label for="japanese_calendar">和暦</label>
<select name="japanese_calendar" id="japanese_calendar">
  <option value="meiji">明治</option>
  <option value="taisho">大正</option>
  <option value="showa">昭和</option>
  <option value="heisei">平成</option>
</select>

画面上は一番先頭にある "明治" が表示されていますが、だからといって次のようなコードを書くと検証に失敗します。("明治"は selected になっていないため)

# NG:検証に失敗する
expect(page).to have_select('和暦', selected: '明治')

「どれも selected ではないこと」をスマートに検証できるメソッドはないので、もしやるとすれば次のようにループを回して全項目が selected でないことを検証する必要があります。

within find_field('和暦') do
  all('option').each do |option|
    expect(option['selected']).to be_blank
  end
end

なお、selectedになっていなくても、valueメソッドを使うと画面上に表示されている項目のvalueを取得できます。

# selected になっていなくても、画面上に表示されている項目のvalueは取得できる 
expect(find_field('和暦').value).to eq 'meiji'

ラジオボタンで特定の項目が選択されていることを検証する

<label>
  <input id="user_sex_male" name="user[sex]" type="radio" value="male" checked="checked">
  男性
</label>
<label>
  <input id="user_sex_female" name="user[sex]" type="radio" value="female">
  女性
</label>
expect(page).to have_checked_field('男性')

title要素の文言を検証する

<html>
<head>
<title>My favorite songs</title>
...
expect(page).to have_title 'My favorite songs'

「表示されていないこと」や「選択されていないこと」を検証する

以下は画面に特定の文字列が表示されていないことを検証するコードです。

expect(page).to_not have_content '秘密のパスワード'

上のコードは次のように to + have_no_content を使って書くこともできます。

expect(page).to have_no_content '秘密のパスワード'

他にも have_no_xxx の形式で検証できる要素があります。

  • have_no_button
  • have_no_checked_field
  • have_no_css
  • have_no_field
  • have_no_link
  • have_no_select
  • have_no_selector
  • have_no_table
  • have_no_text
  • have_no_title
  • have_no_unchecked_field
  • have_no_xpath

hidden項目に設定されている値を検証する

<input type="hidden" name="secret_value" id="secret_value" value="secret!!">

find を普通に使うと画面に表示されている要素しか検索しないので、 visible: false オプションを付けます。

expect(find('#secret_value', visible: false).value).to eq 'secret!!'

フォームの要素がdisabledになっていることを検証する

<label for="blog_title">タイトル</label>
<input type="text" value="" name="blog[title]" id="blog_title" disabled="disabled">

disabledでなければ find_field('タイトル') のように書けますが、disabledだと使えないので、代わりに find + id を使います。

expect(find('#blog_title')).to be_disabled

(2015.10.22 追記)disabledオプションを使って検証する

以下のように disabled: true を指定すれば disabled になっているコントロールも検証できることがわかりました。
こちらの方が自然で理解しやすいと思います。

expect(page).to have_field 'タイトル', disabled: true 

テキストボックスだけでなく、チェックボックスやボタン等でも使えます。

expect(page).to have_checked_field 'メールを受け取る', disabled: true

expect(page).to have_button '更新する', disabled: true 

特定のCSS要素が非表示になっていることを検証する

<div style="display: none;" class="secret-message">
  よい子は見ちゃダメ
</div>

find を普通に使うと画面に表示されている要素しか検索しないので、 visible: false オプションを付けます。

expect(find('.secret-message', visible: false)).to_not be_visible

要素の属性値を検証する

<input type="submit" value="Create User" data-confirm="Are you sure?">
button = find_button 'Create User'
expect(button['data-confirm']).to eq 'Are you sure?'

現在のページが特定のパスであることを検証する

click_on 'New User'
expect(current_path).to eq new_user_path

レスポンスのステータスコードを検証する

click_on 'Create User'
expect(page).to have_http_status(:success)
# または
# expect(page).to have_http_status(:ok)
# expect(page).to have_http_status(200)





find + id/class + action 

 class 
<a class="settings-link" href="/settings">
  <i class="fa fa-gears"></i>
</a>
find('.settings-link').click

id で指定する場合は、ドット(.)ではなくシャープ(#)で指定します。

<a id="settings-link" href="/settings">
  <i class="fa fa-gears"></i>
</a>
find('#settings-link').click

findfind('#some-textbox').set('Hello')  find('#some-checkbox').set(true) 

API



find + id/class +  

 class href
<a class="settings-link" href="/settings">
  <i class="fa fa-gears"></i>
</a>
link = find('.settings-link')
expect(link[:href]).to eq edit_user_path

id で指定する場合は、ドット(.)ではなくシャープ(#)で指定します。

<a id="settings-link" href="/settings">
  <i class="fa fa-gears"></i>
</a>
link = find('#settings-link')
expect(link[:href]).to eq edit_user_path

find + 要素名と、要素内のテキストを組み合わせて取得することも可能です。

<a>About Ruby</a>
# href属性がないと click_link 'About Ruby' ではクリックできないため、以下のようにする
link = find('a', text: 'About Ruby')
link.click

find find('#some-textbox').value  find('#some-checkbox').checked? 

API



Capybara

2
<div class="section-drug">
  現在薬を飲んでいますか?
  <label>
    <input id="user_drug_yes" name="user[drug]" type="radio" value="yes" checked="checked">
    はい
  </label>
  <label>
    <input id="user_drug_no" name="user[drug]" type="radio" value="no">
    いいえ
  </label>
</div>

<div class="section-disease">
  大きな病気にかかったことはありますか?
  <label>
    <input id="user_disease_yes" name="user[disease]" type="radio" value="yes" checked="checked">
    はい
  </label>
  <label>
    <input id="user_disease_no" name="user[disease]" type="radio" value="no">
    いいえ
  </label>
</div>
choose 'はい'
# => Capybara::Ambiguous: Ambiguous match, found 2 elements matching radio button "はい"

このような場合は within を使ってスコープを絞ってから操作を実行します。

within '.section-drug' do
  choose 'はい'
end

within '.section-disease' do
  choose 'いいえ'
end

もしくは「n個ある要素の一番最初の要素を選択」でいい場合はmatch: :firstオプションを付けます。

# 画面上2つある「はい」のうち、最初の「はい」を選択
choose 'はい', match: :first 

Tips:テストしにくいviewはテストをしやすいように変更する

within で絞り込める条件がない(上の例だと、section-drugsection-disease のdivがない)場合は、テストしやすいようにidやclassを付けることを検討してください。

条件に合致する要素を配列として取得する

下のように、3件のデータが表示されているテーブルがあったとします。

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Mozell Conn</td>
      <td>
        <a href="/contacts/1/edit">Edit</a>
      </td>
    </tr>
    <tr>
      <td>Adaline Gleason</td>
      <td>
        <a href="/contacts/2/edit">Edit</a>
      </td>
    </tr>
    <tr>
      <td>Jazmyne Goldner</td>
      <td>
        <a href="/contacts/3/edit">Edit</a>
      </td>
    </tr>
  </tbody>
</table>

このテーブルの中にある2行目の Edit リンクをクリックしたい、という場合は以下のように all メソッドを活用します。

all('tbody tr')[1].click_link 'Edit'

all('tbody tr') tbody  tr

all 2 [1] 2 tr

 tr Edit  click_link 'Edit' 2 Edit 

2022.1.28




 tr
all('tbody tr')[0].click_link 'Edit'

これは first を使うと簡潔に書けます。

first('tbody tr').click_link 'Edit'

応用テクニックして、 within と組み合わせて使うこともできます。

within first('tbody tr') do
  click_link 'Edit'
end

ちなみに、 lastsecond のようなショートカットメソッドはないみたいです。
all('tbody tr').lastall('tbody tr')[1] のように書いてください。

参考: http://www.rubydoc.info/github/jnicklas/capybara/Capybara/Node/Finders

特定のパスへのリンクを検証する/クリックする

ページ内に同じようなリンクが複数あり、特定のリンクだけにフォーカスしたい場合は具体的なパス(a要素のhref属性)で絞り込むこともできます。

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Mozell Conn</td>
      <td>
        <a href="/contacts/1/edit">Edit</a>
      </td>
    </tr>
    <tr>
      <td>Adaline Gleason</td>
      <td>
        <a href="/contacts/2/edit">Edit</a>
      </td>
    </tr>
    <tr>
      <td>Jazmyne Goldner</td>
      <td>
        <a href="/contacts/3/edit">Edit</a>
      </td>
    </tr>
  </tbody>
</table>
contact = Contact.find_by(name: 'Adaline Gleason')

expect(page).to have_link 'Edit', href: edit_contact_path(contact)

click_link 'Edit', href: edit_contact_path(contact)

リンク文字列がない場合(アイコンが表示されている場合など)はhrefだけで絞り込むこともできます。

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Mozell Conn</td>
      <td>
        <a href="/contacts/1/edit">
          <i class="fa fa-pencil"></i>
        </a>
      </td>
    </tr>
    <tr>
      <td>Adaline Gleason</td>
      <td>
        <a href="/contacts/2/edit">
          <i class="fa fa-pencil"></i>
        </a>
      </td>
    </tr>
    <tr>
      <td>Jazmyne Goldner</td>
      <td>        
        <a href="/contacts/3/edit">
          <i class="fa fa-pencil"></i>
        </a>
      </td>
    </tr>
  </tbody>
</table>
contact = Contact.find_by(name: 'Adaline Gleason')

expect(page).to have_link nil, href: edit_contact_path(contact)

click_link nil, href: edit_contact_path(contact)

その他、知っておくと便利なテクニック

テストが失敗する直前の画面をブラウザで開く

以下のように、なぜか失敗するテストがあったとします。

click_on 'Create User'
expect(page).to have_content 'ユーザを作成しました'
# エラー => expected to find text "ユーザを作成しました" in "...

失敗する原因がすぐにわからない場合は save_and_open_page メソッドを使うと、ブラウザが自動的に起動し、その時点の画面を確認できます。
(ただし、CSSは適用されないので見た目は不格好になります)

click_on 'Create User'
# ブラウザで画面を開く
save_and_open_page
expect(page).to have_content 'ユーザを作成しました'

ブラウザの自動起動には launchy gem が必要

"Please install the launchy gem to open the file automatically." という警告が出てブラウザが起動しない場合は、launchy gemをインストールしてください。

# Gemfile
group :test do 
  gem 'launchy'
end
bundle install

テスト失敗時に自動的に save_and_open_page を呼ぶ

テスト失敗時に自動的に save_and_open_page が呼ばれるようにしておくと、効率よくデバッグできるかもしれません。
詳しくは以下の記事を読んでみてください。

フィーチャスペックでテスト失敗時に自動的に save_and_open_page を実行する方法

手っ取り早くテストをskipする

scenarioxscenario に変更するとそのテストはskipされて実行されなくなります。(pending扱いになります)

xscenario '一時的に実行させたくないシナリオ' do
  # ...
end

JavaScriptを使わないと操作できない処理をテストする

Ajaxを使った処理や、クリックイベントによるモーダル画面の表示など、JavaScriptなしでは実行できない操作がある場合は js: true タグを付けます。

scenario 'Userの作成', js: true do
# または
# it 'Userの作成', js: true do

JavaScriptドライバのセットアップ方法について

JavaScriptを実行する場合は、PoltergeistのようなJavaScriptドライバの設定が必要になります。
具体的な手順は以下の記事を参照してください。

初心者大歓迎!RSpec 3でドラッグアンドドロップ機能をテストする方法(スクリーンキャスト付き)

テストが失敗する場合はsleep等でテストを停止させてみる

JavaScriptの処理が完了しないうちにテストが先に進んでしまうとテストが失敗します。
その場合は sleep を挟むなどして、JavaScriptの処理が終わるまでテストを停止させてください。

# Ajaxでデータを保存するテストの例
expect { 
  click_link 'Save'
  sleep 0.5 # 秒数は適当に調整 
}.to change { Item.count }.by(1)

このあたりのテクニックは sleep 以外を使う方法もいろいろあるので、必要に応じてネットの情報等を参考にしてください。
(とはいえ、僕はたいてい sleep を使っているんですが)

2015.5.10 追記:sleepの代わりにfindやhave_xxxを使う方がベターです

JavaScriptを使う操作の後に画面上の表示が変化する場合はfindhave_xxxを使うとCapybaraが自動的に処理が完了するまで(=画面に変化が現れるまで)待ってくれます。(デフォルトの待ち時間は最大2秒間です)

expect { 
  click_link 'Save'
  # sleepの代わりにfindで待つ
  find '.alert', text: '保存しました' 
}.to change { Item.count }.by(1)

# または
click_link 'Save'
# sleepの代わりにhave_selectorで待つ
expect(page).to have_selector '.alert', text: '保存しました'
expect(Item.count).to eq 1 

 @syossan27 


RSpecsleep


2020.9.6  

sleep


sleep feature spec  - Qiita

Capybara調 - Google 



 js: true 

OKNG

 rspec-retry gem使便
group :test do
  # ...
  gem 'rspec-retry'
end
rails_helper.rb
# ...
require 'rspec/retry'

RSpec.configure do |config|
  # ...

  # 実行中にリトライのステータスを表示する
  config.verbose_retry = true
  # リトライの原因となった例外を表示する
  config.display_try_failure_messages = true

  # js: true のフィーチャスペックのみリトライを有効にする
  config.around :each, :js do |ex|
    ex.run_with_retry retry: 3
  end
end

使gemREADME


(hover)


(hover) hover 使
js: true 
scenario '秘密の隠しボタンをクリックする', js: true do
  visit secret_path
  find('.secret-area').hover
  # hover中しか表示されないボタンをクリックする
  find('.secret-button').click
end

リターンキーの押下をシミュレートする

以下の画像のように検索実行ボタンがなく、検索フィールド内でリターンキーを押して検索を実行するフォームを想定します。

Screen Shot 2016-05-07 at 14.13.43.png

<form ()>
<input type="text" id="search-text">
</form>

リターンキーのシミュレートは js: true でJavaScriptを有効にした場合しか実行できません。
以下はJSドライバとしてPoltergeistを使った場合の実行例です。(Poltergeist以外では動作確認していません)

# 検索テキストを入力
fill_in 'search-text', with: 'Capybara'
# テキストボックス内でリターンキーを押下
find('#search-text').native.send_key(:Enter)
# 検索結果の検証
expect(page).to have_content 'Capybaraの検索結果'

HTMLソースを取得する

たとえばHTML要素のサニタイズが適切に行われているかどうかを検証するために、HTMLソースを直接参照したいケースがあります。
以下はページ全体のHTMLを取得するコード例です。

visit root_path
html = page.html
# 取得結果 
# <!DOCTYPE html>
# <html>
# <head>
# ...

特定の要素だけにフォーカスする場合は以下のようにします。

visit root_path

# <div class="navbar">内のHTMLを取得する

# js: true を使わない場合
html = find('.navbar').native.inner_html

# js: true を使う場合 (Poltergeist 1.8以上で有効。Poltergeist以外では動作未確認)
html = find('.navbar')['innerHTML']

User-Agentを偽装する

以下はUser-Agentを iPhone 6(iOS 8.1)に偽装する例です。
テストを実行するドライバによって設定方法が異なるので注意してください。

Capybara単体で実行する場合

user_agent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) CriOS/38.0.2125.67 Mobile/12B411 Safari/600.1.4'

Capybara.current_session.driver.header('User-Agent', user_agent)

Capybara + Poltergeistで実行する場合

user_agent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) CriOS/38.0.2125.67 Mobile/12B411 Safari/600.1.4'

page.driver.headers = { "User-Agent" => user_agent }

プログラミング的にログイン状態を作る/OAuth認証を偽装する

DeviseやOmniAuthなど、メジャーな認証系のgemは、たいていテストを考慮した機能を持っています。
そうした機能を使うとテストコード側でプログラミング的にログイン状態を作ったり、OAuth認証を偽装したりすることができます。

# Deviseでプログラミング的にログイン状態を作る
user = User.create(email: 'foo@example.com')
login_as user, scope: :user
visit edit_settings_path

# OmniAuthでTwitter認証を偽装する
OmniAuth.config.test_mode = true
params = { provider: 'twitter', uid: '123545' }
OmniAuth.config.mock_auth[:twitter] = OmniAuth::AuthHash.new(params)
click_on 'Twitter Login'

使Wiki


How To: Test with Capybara - plataformatec/devise

Integration Testing - intridea/omniauth

API


TwitterFacebookAPI


使API

使


使RSpec3mock使

VCRgem使
VCR12使gem

VCR使Everyday Rails - RSpecRails10

新しいウインドウ(新しいタブ)の内容を検証する

<a href="/some_information" target="_blank">新しいウインドウを開く</a>
scenario '新しいウインドウの内容を検証する', js: true do
  visit some_path
  click_on '新しいウインドウを開く'
  handle = page.driver.browser.window_handles.last
  page.driver.browser.within_window(handle) do
    expect(page).to have_content '新しいウインドウの内容'
  end
end




Capybara使 js: true 

Capybara(2.4.4)Poltergeist(1.5.1)JavaScriptgemAPI


@tyn-iMarket

CapybaraPoltergeist使


使
Qiita


Capybara使

Capybara
9
UI



使RSpec
RSpec使

Rails Everyday Rails - RSpecRails 
Rails使

Everyday Rails - RSpecRails
Everyday Rails
QiitaRubyRailsRSpecQiitaTwitter


@jnchito - Qiita

@jnchito - Twitter




参考文献

1775
1772
8

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

1775
1772