はじめに
普段Capybaraでのメールのテストは主にopen_emailを使っているのですが、他にメソッドがあるのか気になってコードを読んだところ、想像していたよりも色々なケースを想定した便利なメソッドがあったのでまとめてみました。(古いからかまとめている記事がなかったので、、、)
読んだコードは下記
メソッド一覧
各メソッドの説明に「メールを取得する」と記載していますが、正確にはMail::Messageクラスのインスタンスを取得するという意味です。
※コードだけでは理解が怪しい処理は動かして挙動確認もしていますが、もし処理に関して間違ったことを書いている場合はコメントでご指摘いただけるとありがたいです。
find_email(address, opts={})
-
addressを設定している場合- 設定したメールアドレスに1番最初に届いたメールを取得する。
-
optsも設定している場合- hashには
with_subject、with_text、fromのkeyから1つを設定し、設定したkeyによってそれぞれ正規表現によるマッチング(=~)でメールを取得する。 - 複数条件による絞り込みはできないようなので注意が必要。
-
addressに設定されたメールアドレスのメールボックスからマッチングされる。-
with_subject- メールのタイトルでマッチング
-
with_text- メールの本文でマッチング
-
from- 送信者のメールアドレスでマッチング
-
- hashには
open_email(address, opts = {})
addressに指定したメールアドレスの最初のメールを取得する。
opsにはfind_email同様にタイトル(with_subject)、本文に含む文字列(with_text)、送信元のアドレス(from)が指定できる。
メールを取得できなかった場合、find_emailとは異なり例外を発生させる。
エイリアスメソッドにopen_email_forがある。
open_last_email()
全てのアドレスから1番最後に送信されたメールを取得する。
メールを取得できない場合は例外を発生させる。
open_last_email_for(address)
addressに指定したメールアドレスに1番最後に送信されたメールを取得する。
current_email(address=nil)
open_email,open_ast_email, open_last_mail_for によって取得したメールを取得する。これらのopen_***メソッドが実行されていない場合、例外を発生させる。
addressを設定する場合、設定したメールアドレスでopen_***メソッドを実行していないと例外が発生する。
なぜopen_***メソッドを実行していないとエラーが発生するかと言うと、current_emailではemail_spec_hashというプライベートメソッドを呼んでいる。
https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L48
email = address ? email_spec_hash[:current_emails][address] : email_spec_hash[:current_email]
email_spec_hashでは下記のようにメモ化をおこなっており、このメソッドはopen_***メソッドから呼ばれるset_current_emailメソッドから呼ばれているため。
https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L94
def email_spec_hash
@email_spec_hash ||= {:read_emails => {}, :unread_emails => {}, :current_emails => {}, :current_email => nil}
end
メモ化されているのでopen_***を使用後に同じメールを参照する場合、current_emailを使った方がおそらくパフォーマンスは良くなるはず。
visit_in_email(link_text, address = '')
link_textに指定したリンク先に遷移する。
addressが指定されている場合、find_emailを使用して1番最初に届いたメールを取得する。指定されていない場合はcurrent_emailでメールを取得する。
既にcurrent_emailの項目で説明済みですが、先にopen_***メソッドが先に実行されていないと例外が発生する。visit_in_emailの場合もcurrent_emailを使用していて同様なので、addressを設定しない場合は注意が必要。
links_in_email(email) => Array
引数に設定したMail::Messageの本文に含まれるリンクのurlの重複なしの配列を返す。
click_email_link_matching(regex, email = current_email)
regexに設定した正規表現に最初にマッチしたリンク先に遷移する。
emailを設定しない場合はcurrent_emailが実行されるので先にopen_***の実行が必要。マッチするurlがない場合、例外が発生する。
下記のようにlinks_in_emailメソッドを使用して最初にtrueになったurlを取得している。
links_in_email(email).detect { |link| link =~ regex }
click_first_link_in_email(email = current_email)
emailに設定したメール本文に含まれる最初のリンク先に遷移する。
このメソッドも同様にemailを設定しないとcurrent_emailが実行されます。
current_email_attachments(address=nil)
adressを設定した場合、設定したメールアドレスに最初に送信されたメールの添付ファイルを取得する。設定しなかった場合は全てのメールアドレスの最初に送信されたメールの添付ファイルを取得する。添付ファイルを取得できない場合は空の配列を返す。
メソッド名にあるようにcurrent_emailが実行されるので同様に先にopen_***メソッドの実行が必要です。
read_emails_for(address)
open_***メソッドで既に取得されたメールの配列を取得します。取得されたメールがない場合、空の配列を返します。
unread_emails_for(address)
まだ取得されていないメールの配列を取得します。取得されていないメールがない場合、空の配列を返します。