Cypressは基本1つのブラウザを操作するテストツールですが、今回2つのブラウザを操作したいシチュエーションになり、何か方法はないかと色々試してみたので、それの記事をまとめたいと思います。
結論から言うと
2つのブラウザを同時にテストすることはできないが、1つの画面を開きながら、別の画面のAPIを操作することはできる
どんなシチュエーション?
画面Aの入力フィールドに文章入力後、「送信」ボタンを押すと、
画面Bにwebsocket通知がされるようになっている。
この時のAのメッセージ送信APIが叩かれたら、正しくwebsocket通知がされるかをCypressでテストしたい。
つまずいたこと
Cypressは1つのブラウザ内で動作するので、テスト実行時に複数のタブをサポートできない。つまり、2つ以上の画面を開いてテストすることは不可能。
解決策
複数の画面を使って操作したい内容が、APIを叩く行為だった場合、cypress内で直接APIを叩けばいい。
公式にある通り、CypressにはHTTP リクエストを作成する機能があります。
cy.request('POST', 'http://localhost:8888/users/admin', { name: 'Jane' }).then(
(response) => {
// response.body is automatically serialized into JSON
expect(response.body).to.have.property('name', 'Jane') // true
}
)
引用元 Cypressのリクエスト作成について↓
これを使えば、Bの画面を開いた状態で、A画面で叩きたかったAPIを直接叩いて、Bの画面で通知を受け取ることが可能です。
実際にコードを見てみます
A画面のvue.js
<template>
<a>送りたいメッセージ<a>
<input v-model="message" data-cy="message">
<button @click="sendMessage" data-cy="send">送信</button>
</template>
<script>
export default {
data() {
return {
message: "",
};
},
methods: {
sendMessage() {
let result = await axios.post(
process.env.VUE_APP_SEND_MESSAGE_API,
{message: this.message}
)
},
},
}
B画面のvue.js
<template>
<p>画面B</p>
<p>受け取ったメッセージ<p>
<p data-cy="message">{{message}}<p>
</template>
<script>
export default {
data() {
return {
message: ""
};
},
async created() {
this.connection = new WebSocket(process.env.VUE_APP_WEBSOCKET);
this.connection.onmessage = (event) => {
console.log('受け取ったmessage', event);
let parsed = JSON.parse(event.data);
this.message = parsed.message;
};
this.connection.onopen = () => this.connection.send("B画面");
}
}
</script>
Cypressでテストを書いていく!
// 画面Bを開く
cy.visit('/b')
// websocketの接続情報が登録されるのを待つ...🔴下に補足あり
cy.wait(3*1000)
// A画面にあるメッセージ送信APIを直接叩いている
cy.request({
method: 'POST',
url: 'メーセージを送信するボタンについてたエンドポイント ⭐️下に補足あり',
body:{
message: "テストメッセージ"
}
}).then((response) => {
// A画面で送信されたメッセージが、表示されているかの確認
cy.get([data-cy="message"]).should('have.text', "テストメッセージ");
});
shoudは、想定される表示になるのを(4秒まで)待って判定してくれるメソッドなので、通知が遅れても拾ってくれます。遅れすぎる場合は、
cy.get([data-cy="message"], { timeout: 3*1000 }).should('have.text', "テストメッセージ");
こんな感じにして、表示を待つ時間を伸ばしても良さそうです。
補足
🔴...このwaitがないと、どのブラウザが開かれて、通知を送る場合どのブラウザに送るのかの住所になるconnection_idを貼る時間がないため、websocket通知が飛ばないことがあったので注意。waitを入れたら解消されました。
⭐️...url: 'メーセージを送信するボタンについてたエンドポイント'は、
叩きたいAPIを実際に叩くと、開発者ツールのネットワークでも確認できます。
CypressでWebsocketのテストを行うことについて
Cypressのcy.request()コマンドは REST エンドポイントのみに限定されているため、websocketのテストをすることは既存のものでは難しいようです。
また「cypress websocket」で調べると、日本語の記事が全然出てきません。(2024年4月時点)
海外の方が作ってくれたwebsocketのテストツールがgitHubで公開されていますが、自分には正直難しかった…。そのため、できる限り、簡単に、直感的にwebsocketを叩けないかということで、こういった方法をとりました。しかし、これはWebsocket通知のトリガーがRESTエンドポイントであることが必須条件であることに加え、本来のWebsocketのテストツールを使った方法ではないので、邪道だと思います。
CypressのWebsocket通知テストについては、まだまだ情報が少ないので、わかったら共有していきたいです。