CypressでCognitoにログインするテストケースを通すのに苦労したポイント

# 概要

* cypressを初めて使う筆者が
* cognitoを認証基盤に利用するwebアプリに
* ログインするテストケースを作った際にハマったポイントまとめ

# 先に結論

ここのコードに解決策が全部入ってるからこれ見ればok
https://gist.github.com/vittorio-nardone/a9b388ff7388a4ae7343cd6a2758bc4b


# 背景

最初、cypressをcognitoに使った事例探したらクラメソさんの記事があって、
https://dev.classmethod.jp/articles/amplify-console-cypress/

助かったー、と思いつつ参考にして実践してみたがだめだったので、色々と試行錯誤した軌跡


# ハマったポイント


## セレクタで入力フォームを取得できない

ログイン画面を表示させて、inputタグに入力すべくセレクタで指定したが、見つからないエラー

```javascript
describe("Login Test", () => {
  it('Shows Login', () => 
    cy.visit('https://xxxx/login')
    cy.get('[data-test="sign-in-username-input"]')
  })
}
```

これを実行すると、見つかりません、と言われます。

![cypress_error_selector.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1533/3cfa4552-dd9f-8608-2ebd-6ef384dfdc72.png)

```
Timed out retrying after 4000ms: Expected to find element: [data-test="sign-in-username-input"], but never found it.
```

入力フォームのタグを確認したら `data-test="sign-in-username-input"` 要素は間違いなくある

```html
<input id="username" type="text" placeholder="xxx" class="input" data-test="sign-in-username-input">
```

なのになぜ？

iframeの影響か？いや使ってないな、とか
タグが深くなったら届かない？とか
`amplify-sign-in` タグまで辿れてその先の `amplify-form-section` が辿れないのなんでやとか
色々調べましたが、解決には至らない

https://twitter.com/papettoTV/status/1371979545696301059

キレてる。怖い。

### 解決策

cypressのgetにオプション `{ includeShadowDom: true }` をつけて解決しました。


```javascript
cy.get('[data-test="sign-in-username-input"]', { includeShadowDom: true })
```

参考） https://docs.cypress.io/api/commands/get.html#Arguments



### 原因

コンソールログを見ると `#shadow-root(open)` って表記があります。
![cypress_console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1533/c5b1f2f1-2a40-ca3f-7251-bb768abff682.png)


**なんそれ**

[shadow DOM](https://developer.mozilla.org/ja/docs/Web/Web_Components/Using_shadow_DOM)

コンポーネントっぽくDOMを利用できるっぽいなにからしい（かなり浅い理解
まあ、なんせshadowって言ってるぐらいなんで、隠れてるんでしょうね。なので、セレクタが見つけれなかったと。
で、それでも見つけてくれるオプション `includeShadowDom` ができたと。

デフォルト `true` じゃあかん？
と思ったら、configurationにあるので変えれそう

https://docs.cypress.io/guides/references/configuration.html#Global


## パスワード入力フォームにtypeできない

ログインIDはセレクタで取得しtypeで入力できたので、次パスワード、と意気込むとこのエラーがでました。
![cypress_password_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1533/82e7009c-5269-2fa7-736d-c4eecf6ed42f.png)


```
cy.type() failed because it targeted a disabled element.
  > <input id="password" type="password" placeholder="パスワード" class="input" data-test="sign-in-password-input">
Ensure the element does not have an attribute named disabled before typing into it.
```

なんか途中のinputタグの表現がキレてる。今度は私じゃなくてタグがキレてる。怖い。

エラー文にあるような、 `disabled` な要素になってないのは確認した。
で、ググってみると同様の現象はあるようで、以下のように解決してた。

```javascript
    cy.get('[slot="sign-in"]').find('#password', { includeShadowDom: true }).click({force: true})
    cy.get('[slot="sign-in"]').find('#password', { includeShadowDom: true }).type('password')
```

一回 `.click({force: true})` で強制クリックでフォーカスしておいて type() すると。なるほど。
これで動作した。

が、結論にのせたgistにもっとスマートな方法があった

```javascript
    cy.get('[slot="sign-in"]').find('#password',{ includeShadowDom: true } ).type('password', {log: false, force: true})
```
type() に `force:true` optionあるやん。１行ですむやん。素敵やん。
 

## ローカル環境でAPIリクエストが502 Bad Gateway

これらをクリアし、いざログインしてみると、
なぜかAPIリクエストのレスポンスが502 Bad Gateway で返ってくる。ちなみに以下のような構成。

![cypress_local_dev_env.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1533/c3f7f431-60db-def3-79b8-e20bf65bab9c.png)



* AWS上の開発環境だと問題なかった
* Cognitoから返ってきてるIdTokenの中身をdecodeしてみたが、開発環境とほぼ変わらず問題なさそうに見えた

もちろん、素のchromeだと期待通り動作する。
なので、違うのはブラウザの違いぐらいかな、とか思いながらまだ未解決

追記）解決した

### 原因

認可処理で、アプリケーション（lambda） で受け取る変数 `event.header.Authorization` が、
cypress上のブラウザからのリクエストだと `event.header.authorization` になってた。

cypressが投げるリクエストヘッダは `Authorization` なので、何故、誰が小文字にしたのかは謎。

ServerlessFrameworkをローカルで動かすプラグインservlerless framework offlineのせいかな・・・？