email_specのhelperメソッドのチートシート

## はじめに
普段Capybaraでのメールのテストは主に`open_email`を使っているのですが、他にメソッドがあるのか気になってコードを読んだところ、想像していたよりも色々なケースを想定した便利なメソッドがあったのでまとめてみました。(古いからかまとめている記事がなかったので、、、)

読んだコードは下記

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb

https://www.rubydoc.info/gems/email_spec/EmailSpec/Helpers#open_email-instance_method

## メソッド一覧

各メソッドの説明に「メールを取得する」と記載していますが、正確には`Mail::Message`クラスのインスタンスを取得するという意味です。

※コードだけでは理解が怪しい処理は動かして挙動確認もしていますが、もし処理に関して間違ったことを書いている場合はコメントでご指摘いただけるとありがたいです。


### find_email(address, opts={})

- `address`を設定している場合
  - 設定したメールアドレスに1番最初に届いたメールを取得する。
- `opts`も設定している場合
  - hashには`with_subject`、`with_text`、`from`のkeyから1つを設定し、設定したkeyによってそれぞれ正規表現によるマッチング(`=~`)でメールを取得する。
  - 複数条件による絞り込みはできないようなので注意が必要。
  - `address`に設定されたメールアドレスのメールボックスからマッチングされる。
    - `with_subject`
      - メールのタイトルでマッチング
    - `with_text`
      - メールの本文でマッチング
    - `from`
      - 送信者のメールアドレスでマッチング

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L72


### open_email(address, opts = {})

`address`に指定したメールアドレスの最初のメールを取得する。
`ops`には`find_email`同様にタイトル(`with_subject`)、本文に含む文字列(`with_text`)、送信元のアドレス(`from`)が指定できる。
メールを取得できなかった場合、`find_email`とは異なり例外を発生させる。
エイリアスメソッドに`open_email_for`がある。

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L32

### open_last_email()

全てのアドレスから1番最後に送信されたメールを取得する。
メールを取得できない場合は例外を発生させる。

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L38

### open_last_email_for(address)

`address`に指定したメールアドレスに1番最後に送信されたメールを取得する。


https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L42

### 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

```rb
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

```rb
def email_spec_hash
    @email_spec_hash ||= {:read_emails => {}, :unread_emails => {}, :current_emails => {}, :current_email => nil}
end
```

メモ化されているので`open_***`を使用後に同じメールを参照する場合、`current_email`を使った方がおそらくパフォーマンスは良くなるはず。

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L46


### visit_in_email(link_text, address = '')

link_textに指定したリンク先に遷移する。

addressが指定されている場合、`find_email`を使用して1番最初に届いたメールを取得する。指定されていない場合は`current_email`でメールを取得する。

既に`current_email`の項目で説明済みですが、先に`open_***`メソッドが先に実行されていないと例外が発生する。`visit_in_email`の場合も`current_email`を使用していて同様なので、`address`を設定しない場合は注意が必要。

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L12

### links_in_email(email) => Array

引数に設定した`Mail::Message`の本文に含まれるリンクのurlの重複なしの配列を返す。

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L87

### click_email_link_matching(regex, email = current_email)

`regex`に設定した正規表現に最初にマッチしたリンク先に遷移する。
`email`を設定しない場合は`current_email`が実行されるので先に`open_***`の実行が必要。マッチするurlがない場合、例外が発生する。

下記のように`links_in_email`メソッドを使用して最初にtrueになったurlを取得している。

```rb
links_in_email(email).detect { |link| link =~ regex }
```

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L21

### click_first_link_in_email(email = current_email)

`email`に設定したメール本文に含まれる最初のリンク先に遷移する。
このメソッドも同様に`email`を設定しないと`current_email`が実行されます。

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L27

### current_email_attachments(address=nil)

`adress`を設定した場合、設定したメールアドレスに最初に送信されたメールの添付ファイルを取得する。設定しなかった場合は全てのメールアドレスの最初に送信されたメールの添付ファイルを取得する。添付ファイルを取得できない場合は空の配列を返す。

メソッド名にあるように`current_email`が実行されるので同様に先に`open_***`メソッドの実行が必要です。

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L58

### read_emails_for(address)

`open_***`メソッドで既に取得されたメールの配列を取得します。取得されたメールがない場合、空の配列を返します。

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L67

### unread_emails_for(address)

まだ取得されていないメールの配列を取得します。取得されていないメールがない場合、空の配列を返します。

https://github.com/email-spec/email-spec/blob/main/lib/email_spec/helpers.rb#L62