【Day 20】ブログ一覧を取得し、表示する - API E2E

## はじめに

![スライド21.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/4939d6e0-b55f-8ddb-d064-6e73696af850.png)

---

**2023年アドベントカレンダー20日目**です。

https://qiita.com/advent-calendar/2023/life-sync-app

本日から「ユーザーはトップページでブログタイトルの一覧を見ることができる」を進めていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/6eb0ef2a-c7f4-7a75-add7-a866d28b214d.png)

## E2E

前回整備したように`Gauge` + `TypeScript`でE2Eテストを書いていきます

以前初期値を入れたものを参考にして、次のようにSpecファイルを作成しました。

```spec:blog.spec
# ブログ一覧取得系

## Get Blogs

* URL"http://localhost:3000/blogs"にGETリクエストを送る
* レスポンスステータスコードが"200"である
* レスポンス内JsonBodyの"blogs[0].id"が文字列の"123e4567-e89b-12d3-a456-426614174000"である
* レスポンス内JsonBodyの"blogs[0].title"が文字列の"カフェの隅で見つけた幸せ：私のお気に入りの隠れ家"である
* レスポンス内JsonBodyの"blogs[0].author"が文字列の"田中太郎"である
* レスポンス内JsonBodyの"blogs[0].body"が文字列の"ブログの本文"である
* レスポンス内JsonBodyの"blogs[0].createdAt"が文字列の"2023-12-09 09:00:00"である
```

作ったStepは3種類

- URL`<url>`にGETリクエストを送る
- レスポンスステータスコードが`<statusCode>`である
- レスポンス内JsonBodyの`<jsonPath>`が文字列の`<value>`である

このテストコードを実装してみます。

```typescript:fetch.ts
import axios, { AxiosResponse } from 'axios'
import { assert } from 'chai'
import { Step, DataStore, DataStoreFactory } from 'gauge-ts'

// jsonとpathからValueを抽出するメソッド
const extractValue = (json: Object, path: string) => {
  const parts = path.split(/[\.\[\]\'\"]/).filter(p => p);
  let value = json

  parts.map((part) => {
    if (value[part] === undefined) {
      return undefined
    }
    value = value[part]
  })

  return value
}

export default class BlogStep {
  @Step('URL<url>にGETリクエストを送る')
  public async requestGet(url: string) {
    const response = await axios.get(url)
    let suiteStore: DataStore = DataStoreFactory.getSuiteDataStore()
    suiteStore.put('response', response)
  }

  @Step('レスポンスステータスコードが<statusCode>である')
  public async checkStatusCode(statusCode: string) {
    let suiteStore: DataStore = DataStoreFactory.getSuiteDataStore()
    const response: AxiosResponse<any, any> = suiteStore.get('response')
    assert.equal(response.status, parseInt(statusCode))
  }

  @Step('レスポンス内JsonBodyの<jsonPath>が文字列の<str>である')
  public async checkJsonResponseString(jsonPath: string, str: string) {
    let suiteStore: DataStore = DataStoreFactory.getSuiteDataStore()
    const response: AxiosResponse<any, any> = suiteStore.get('response')
    assert.equal(extractValue(response.data, jsonPath), str)
  }
}
```

少しだけ解説します。

### GETリクエスト

```typescript
  @Step('URL<url>にGETリクエストを送る')
  public async requestGet(url: string) {
    const response = await axios.get(url)
    let suiteStore: DataStore = DataStoreFactory.getSuiteDataStore()
    suiteStore.put('response', response)
  }
```

1. パラメータ`URL`を受け取り、GETリクエストを送る
1. gaugeのDataStoreにresponseを格納

### ステータスコードチェック

```typescript
  @Step('レスポンスステータスコードが<statusCode>である')
  public async checkStatusCode(statusCode: string) {
    let suiteStore: DataStore = DataStoreFactory.getSuiteDataStore()
    const response: AxiosResponse<any, any> = suiteStore.get('response')
    assert.equal(response.status, parseInt(statusCode))
  }
```

1. 先ほど格納した`response`を取り出す
1. `respons`の`status`と、パラメータの`StatusCode`を比べる

### JsonのValueチェック

```typescript
// jsonとpathからValueを抽出するメソッド
const extractValue = (json: Object, path: string) => {
  const parts = path.split(/[\.\[\]\'\"]/).filter(p => p);
  let value = json

  parts.map((part) => {
    if (value[part] === undefined) {
      return undefined
    }
    value = value[part]
  })

  return value
}

// ...

  @Step('レスポンス内JsonBodyの<jsonPath>が文字列の<str>である')
  public async checkJsonResponseString(jsonPath: string, str: string) {
    let suiteStore: DataStore = DataStoreFactory.getSuiteDataStore()
    const response: AxiosResponse<any, any> = suiteStore.get('response')
    assert.equal(extractValue(response.data, jsonPath), str)
  }
```

1. 先ほど格納した`response`を取り出す
1. オリジナルの、Jsonから、pathを指定してValueを抽出するメソッドを作成
1. `respons`の`jsonPaht`の`value`と、パラメータの`str`を比べる

解説は以上です。

### 実行

実行してみます

```bash
$ gauge run specs
# Blog E2E
  ## Get Blogs   ✘

<<省略>>

Successfully generated html-report to => /your/path/reports/html-report/index.html

Specifications: 1 executed      0 passed        1 failed        0 skipped
Scenarios:      1 executed      0 passed        1 failed        0 skipped

Total time taken: 128ms
```

実装がまだなので、予想通り失敗しました :ok:

次回はAPIをRust + Axumを使ってクリーンアーキテクチャに基づいて作成していきます