devise_token_auth ログアウトのテストコード実装時に苦戦したことをまとめる

devise_token_auth でログアウトのテストコード作成時、エラー解決の情報が少なかったのでまとめます。
※ user の新規登録、ログイン、ログアウト機能を実装しているものとします。
※ FactoryBot を導入してます。

## headers にログインに必要な情報が入っていないため、エラー発生

エラー発生時のコード

```
describe "DELETE /v1/auth/user/sign_out" do
  subject { delete(destroy_v1_user_session_path) }
  context "トレーナーログアウト時" do
    let(:user) { create(:user) }
    it "トークンを無くし、ログアウトできる" do
      subject
      expect(response).to have_http_status(200)
    end
  end
end
```

エラー内容

```
Failure/Error: expect(response).to have_http_status(200)
expected the response to have status code 200 but it was 404
```
正常なレスポンス(200)ではなく、リクエストが存在しない(404)エラーが出てます。との内容。
subject の下に binding.pry を入れ、デバック画面にし`user` を実行

```
#<Trainer id: 532, provider: "email", uid: "6_hannah@emmerich.name", allow_password_change: false, name: "松本 七海", nickname: nil, email: "6_hannah@emmerich.name", address: nil, birthday: nil, created_at: "2020-07-26 06:10:35", updated_at: "2020-07-26 06:10:35">
```
user の中にデータがあることを確認できました。
次に headers 情報を確認するため、`response.headers` を実行。

```
{"X-Frame-Options"=>"SAMEORIGIN",
 "X-XSS-Protection"=>"1; mode=block",
 "X-Content-Type-Options"=>"nosniff",
 "X-Download-Options"=>"noopen",
 "X-Permitted-Cross-Domain-Policies"=>"none",
 "Referrer-Policy"=>"strict-origin-when-cross-origin",
 "Content-Type"=>"application/json; charset=utf-8",
 "Cache-Control"=>"no-cache",
 "X-Request-Id"=>"a2ad39e6-d2b2-4ae8-93c1-5ddcd2ea22d1",
 "X-Runtime"=>"0.010570",
 "Content-Length"=>"71"}
 ```
headers の情報は返ってきましたが、ログアウトに必要な情報
 `access-token`、`client`、`uid` が入ってないことが分かります。
headers  にログアウトに必要な情報が入ってないから、404の異常系のエラーが発生している。
新規作成時、ログイン時にトークン情報が発行され、その情報をもとにログアウトの処理を行うのですが、現状のコードでは user の情報は作成されても、トークン情報は作成されていない状況です。
なので、トークン情報を入れてあげましょう。

```
describe "DELETE /v1/auth/user/sign_out" do
  subject { delete(destroy_v1_user_session_path, headers: headers) }
  context "トレーナーログアウト時" do
    let(:user) { create(:user) }
    let(:headers) { user.create_new_auth_token }
    it "トークンを無くし、ログアウトできる" do
      subject
      expect(response).to have_http_status(200)
    end
  end
end
```
`create_new_auth_token`メソッドで、必要なメタデータ全てを含む新しい認証トークンを作成します。
subject の下に binding.pry を入れ`headers`を実行し、データが入っていればオッケーです。

## ログアウト時にトークン情報が残ったままのため、エラー発生
ログアウトは、「有効なトークン情報がなくなる」なので、先ほどのコードにトークン情報の有無を確認するテストコードを追記しました。

```diff
describe "DELETE /v1/auth/user/sign_out" do
    subject { delete(destroy_v1_user_session_path, headers: headers) }
    context "トレーナーログアウト時" do
      let(:user) { create(:user) }
      let(:headers) { user.create_new_auth_token }
      it "トークンを無くし、ログアウトできる" do
        subject
+       expect(user.tokens).to be_blank
        expect(response).to have_http_status(200)
      end
    end
  end
```
エラー内容

```
Failure/Error: expect(trainer.tokens).to be_blank
expected `{"LT4SdlN2czyzNnwTfLGjTw"=>{"expiry"=>1596957557, "token"=>"$2a$10$BgZ4YItos1hQRTp4y1JvZ.mIsreaIxD1NC3ckRk0euxsk8IBkoM7K", "updated_at"=>"2020-07-26 07:19:17 UTC"}}.blank?` to return true, got false
```
トークン情報が残ったままとのエラーです。
ログアウトに必要な情報を user に入れ、ログアウトの処理はできても、user の値は更新されないので残ったままになっています。
user の値を更新するためには、`user.reload.token`と記述してあげる必要があります。

```
describe "DELETE /v1/auth/user/sign_out" do
    subject { delete(destroy_v1_user_session_path, headers: headers) }
    context "トレーナーログアウト時" do
      let(:user) { create(:user) }
      let(:headers) { user.create_new_auth_token }
      it "トークンを無くし、ログアウトできる" do
        subject
        expect(user.reload.tokens).to be_blank
        expect(response).to have_http_status(200)
      end
    end
  end
```

以上の内容にすれば、ログアウト後の user の値が更新されるため、user にトークン情報がなくなります。