playwrightでAxios通信時のデータをテストする

playwright
スポンサーリンク

最近、UIを作るにあたってテストの重要性を感じるようになってきていて、E2Eテストのplaywrightを試しで使っています

その中で今回はAxiosの通信の中身を確認するテストをplaywrightで作成します

例えば、UIのボタンを押すと、同じPCのlocalhostのAPIサーバにアクセスしたり、外部のAPIサーバにアクセスしたのをテストで確認する想定です

「画面内のボタンが押されたらAxiosを使ってAPIサーバへ通信して、その通信が正しいか」
ということをテストで確認したいと思っています

create-react-appでベースとなるプロジェクトを作成

今回はcreate-react-appでプロジェクトを作ります

Next.jsでも何でも大丈夫です

npx create-react-app playwright-test --template typescript

playwrightのインストール

cd playwright-test
npm init playwright@latest

App.tsxの編集

import { useState } from 'react';
import axios from 'axios';

function App() {

  const [postResult, setPostResult] = useState("not post");
  const [getReslt, setGetResult] = useState("not get")

  function onClickPostAxios(){
    axios.post('https://httpbin.org/post', {
      firstName: 'Fred',
      lastName: 'Flintstone'
    })
    .then(function (response) {
      setPostResult("POST")
    })
    .catch(function (error) {
      console.log(error);
    });
  }

  function onClickGetAxios(){
    axios.get('https://httpbin.org/get', {
      params:{
        ID: 12345
      }
    }).then(function (response){
      setGetResult("GET")
    })
  }

  return (
    <div className="App">
      <button onClick={onClickPostAxios}>Axios POST Data</button>
      <text>Post Result:</text>
      <text data-testid= "post_result">{postResult}</text>
      <br></br>
      <button onClick={onClickGetAxios}>Axios GET Data</button>
      <text>Get Result:</text>
      <text data-testid = "get_result">{getReslt}</text>
    </div>
  );
}

export default App;

編集したら以下のコマンドで起動します

npm run start

localhost:3000にアクセスような画面が表示されます

「Axios POST Data」ボタンを押すと、https://httpbin.org/postへPOSTリクエスト送り、成功すれば「not post」→「POST」へ変化します

「Axios GET Data」ボタンを押すと、https://httpbin.org/getへGETリクエストを送り、成功すれば「not get」→「GET」へ変化します

テストコードの作成

今回は最初に書いたように、画面内のボタンが押されたらAxiosを使ってAPIサーバへ通信して、その通信が正しいかを確認します

また、通信に成功した場合、表示も変わるのでこれもチェックします

ファイル名は「axiosTest.spec.ts」にして、このファイルをplaywrightインストール時に自動で作られたtestsファイルに入れます

import { test, expect } from '@playwright/test';

test("POSTボタンが押されたときの通信を確認するテスト", async ({ page }) => {
  // httpbinにリクエストが送られたときにここで受け取る
  await page.route('https://httpbin.org/post', route => {
    const request = route.request();
    // 送られたリクエストがPOSTリクエストかどうかを判定
    if (request.method() === 'POST') {
        console.log("POST DATA!!!")
        // postData()にPOSTされたJSONデータが入っているのでパースして判定する
        expect(JSON.parse(request.postData() ?? "nodata")).toEqual({
            firstName: "Fred",
            lastName: "Flintstone"
        });
        // ここでレスポンスを返す
        route.fulfill({
          status: 200, // HTTPステータスコード
          contentType: 'application/json', // コンテンツタイプ
          body: JSON.stringify({ // レスポンスボディ
            data: "Response from mock"
          })
        });
    }
    // console.log(request)
    // リクエストを続行
    // route.continue();
  })

  // ローカルホストに立てているページにアクセスする
  await page.goto('http://localhost:3000/');

  // Axios POST Dataボタンを押す
  await page.getByTestId('postButton').click()

  // 表示がPOSTになったかを確認
  const POSTtext = await page.textContent('[data-testid="postResult"]');
  expect(POSTtext).toBe("POST")
});

test("GETボタンが押されたときの通信を確認するテスト", async ({ page }) => {
  // httpbinにリクエストが送られたときにここで受け取る
  await page.route('https://httpbin.org/get', route => {
    const request = route.request();
    // 送られたリクエストがGETリクエストかどうかを判定
    if (request.method() === 'GET') {
        console.log("GET DATA!!!")
        // ここでレスポンスを返す
        route.fulfill({
          status: 200, // HTTPステータスコード
          contentType: 'application/json', // コンテンツタイプ
          body: JSON.stringify({ // レスポンスボディ
            data: "Response from mock"
          })
        });
    }
    // console.log(request)
    // リクエストを続行
    // route.continue();
  })

  // ローカルホストに立てているページにアクセスする
  await page.goto('http://localhost:3000/');

  // Axios POST Dataボタンを押す
  await page.getByTestId('getButton').click()

  // 表示がPOSTになったかを確認
  const GETtext = await page.textContent('[data-testid="getResult"]');
  expect(GETtext).toBe("GET")
});


今回のテストコードの重要点

今回の一番重要な部分は「どのようにAxiosの通信先を元のコード変えないままテストコードへ誘導するか?」

これにはRoute機能を使います

Route | Playwright
Whenever a network route is set up with page.route() or browserContext.route(), the Route object allows to handle the route.

テストコードの中のこの部分です

 await page.route('https://httpbin.org/post', route => {

Route機能で通信先のAPIサーバのモックを作り、ここで送信した通信内容のテストを行います

今回はメソッドの判定と中のbodyデータの判定を行っています

また、GET関数はURLがクエリで動的に変わってしまうのですが、これはワイルドカードで対応すれば良さそうです

テストの実行

UIの立ち上げ

npm run start

テストの立ち上げ

npx playwright test axiosTest.spec.ts --ui

テストの実行

画面左の緑三角ボタンを押すとテストが実行されます

まとめ

AxisoのPOST関数の通信時のデータの中身をテストする方法について書きました

Jestの単体テストでは「ボタンが実際に押されててAxiosがデータを送信する」流れのテストが書きにくかったのでE2Eのplaywrightを使って書いてみました

この方法が正しいのかわかりませんがとりあえず想定通りの挙動を示したので良しとします

今回作成したプログラムは参考文献の一番下に置いておきます

参考文献

Mock APIs | Playwright
Introduction
APIクライアント開発時のモックに使えるhttpbinの紹介 - Qiita
今すぐ使えるAPIサーバーのモックがほしい自分でAPIサーバーのモック作るのはちょっとめんどいなぁ。。と思った時にいつもお世話になっているhttpbinをご紹介します。使い方https://…
PlaywrightでAPIをモックする 〜PokéAPIでヌオーさんを優勝させる〜
POST リクエスト | Axios Docs
Locators | Playwright
Introduction
GitHub - Mozyanari/playwright-test-axios
Contribute to Mozyanari/playwright-test-axios development by creating an account on GitHub.

コメント

タイトルとURLをコピーしました