取り組み概要
本記事では、Claude CodeとPuppeteerを活用した試験自動化の流れを紹介します。
試験項目表についてもmdファイルを活用してClaude Codeで作成しましたが、今回はPuppeteerでサンプルサイトを自動操作して試験を行うところに焦点を当てました。
準備
実行環境:JavaScript(Node.js)
ブラウザ操作ツール:Puppeteer
ライブラリインストール
Claude Codeが出した手順に基づいてコマンド実行。
例えば「Puppeteerを使いたい」「Excelの試験項目表を読み取ってほしい」「試験結果はExcelに出力してほしい」などの要望を伝えると、以下のように手順を示してくれます。
==========================================
ステップ3: 必要なパッケージのインストール
==========================================
# Puppeteerをインストール
npm install puppeteer
# Excelファイル読み込み用ライブラリをインストール
npm install xlsx
# 結果出力用(Excelファイル作成)
npm install exceljs
試験自動化までのステップ
試験エンジン(JS)を作成
試験項目表の読み取りや、Puppeteerによるブラウザ操作・キャプチャ取得等、試験に関する処理を行うJavaScriptを作成。
こちらも要望を伝えるとClaude Codeがテンプレートを作成してくれます。
// ==========================================
// 定数定義
// ==========================================
const EXCEL_FILE = path.join(__dirname, 'test_data', 'テスト項目表.xlsx');
// ==========================================
// Excel操作関数
// ==========================================
/**
* Excelファイルからテストケースを読み込む
*
* @param {string} testIdFilter - 特定のテストIDのみ取得(カンマ区切り)
* @param {string} screenFilter - 特定の画面名のみ取得
* @returns {Array} テストケースの配列
*/
function loadTestCases(testIdFilter = null, screenFilter = null) {
log(`Excelファイル読み込み: ${EXCEL_FILE}`);
if (!fs.existsSync(EXCEL_FILE)) {
log(`Excelファイルが見つかりません: ${EXCEL_FILE}`, 'ERROR');
process.exit(1);
}
// Excelファイルを読み込む
const workbook = XLSX.readFile(EXCEL_FILE);
const sheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[sheetName];
const data = XLSX.utils.sheet_to_json(worksheet);
log(`テストケース総数: ${data.length}件`);
試験実行
以下コマンドを実行 ※--test-id=1:項番1のみ実行
node tests/run_tests.js --test-id=1
実際に動かしてみたコード例とキャプチャ
入力チェック・登録・編集・削除等、基本的な処理については一通り実施可能になりました。今回は登録・削除について、コード例とキャプチャを抜粋しました。
※コードはClaude Codeに指示して生成されたものです
登録機能
試験項目表に (id):(値) の形式で記載した入力値について、idで入力欄を検索し値を入力する。idについては試験項目表作成時にソースより抽出するよう指示。入力値については入力チェックを考慮するよう指示してClaude Codeが考えたもの。
// 入力操作を実行(「入力」キーワードまたは (id):(値) 形式がある場合)
if (inputValue.includes('入力') || hasIdValueFormat) {
await executeInputAction(page, inputValue);
}
/**
* 入力操作を実行
*
* @param {object} page - Puppeteerのページオブジェクト
* @param {string} inputValue - 入力値(操作内容)
*/
async function executeInputAction(page, inputValue) {
try {
// 入力値を行ごとに分割
const lines = inputValue.split('\n').map(line => line.trim()).filter(line => line);
log(` 入力処理開始: ${lines.length}行を処理`);
for (const line of lines) {
// (id):(値) の形式をチェック
const idValueMatch = line.match(/^([a-zA-Z0-9_-]+)\s*[::]\s*(.+)$/);
if (idValueMatch) {
const fieldId = idValueMatch[1].trim();
const value = idValueMatch[2].trim();
// idでフィールドを検索して入力
const field = await page.$(`#${fieldId}`);
(中略)
// input/textareaの場合
await field.type(value);
log(` → [${fieldId}] に「${value}」を入力しました`);
削除機能
試験項目表において、「キャンセル」または「キャンセル」「押下」を含む場合はキャンセルボタン、それ以外の場合は削除ボタンを押下。
// モーダルの削除/キャンセルボタンをクリック
// キャンセルが明示されている場合
const shouldCancel = inputValue.includes('「キャンセル」') ||
(inputValue.includes('キャンセル') && inputValue.includes('押下'));
// キャンセルが指定されていない場合は削除ボタンをクリック(デフォルト動作)
const shouldDelete = !shouldCancel;
if (shouldCancel) {
const modalClicked = await page.evaluate(() => {
const cancelBtn = document.getElementById('deleteModalCancel');
if (cancelBtn) {
cancelBtn.click();
return true;
}
return false;
});
} else {
// デフォルト: 削除ボタンをクリック
const modalClicked = await page.evaluate(() => {
const confirmBtn = document.getElementById('deleteModalConfirm');
if (confirmBtn) {
confirmBtn.click();
return true;
}
return false;
});
(おまけ)ログとブラウザを1画面に収める工夫
ログとブラウザを同時に確認できるようにするため、Claude Codeに指示してウィンドウサイズと倍率を調整できるようにしました。(+の行を追加)
.option('--screen <name>', '実行する画面名(部分一致)')
.option('--headless <boolean>', 'ヘッドレスモード', 'true')
.option('--slow-mo <ms>', 'スローモーション(ミリ秒)', '0')
+ .option('--window-x <x>', 'ブラウザウィンドウのX座標', '0')
+ .option('--window-y <y>', 'ブラウザウィンドウのY座標', '0')
+ .option('--window-width <width>', 'ブラウザウィンドウの幅', '1280')
+ .option('--window-height <height>', 'ブラウザウィンドウの高さ', '900')
+ .option('--zoom <level>', 'ブラウザ内の表示倍率(0.5〜1.5、1.0が100%)', '1.0')
(中略)
// Puppeteerブラウザ起動
const headless = options.headless !== 'false';
const slowMo = parseInt(options.slowMo, 10);
+ const windowX = parseInt(options.windowX, 10);
+ const windowY = parseInt(options.windowY, 10);
+ const windowWidth = parseInt(options.windowWidth, 10);
+ const windowHeight = parseInt(options.windowHeight, 10);
+ const zoomLevel = parseFloat(options.zoom);
試験実行コマンドに引数として追加
node tests/run_tests.js --headless=false --test-id=14 --window-x=960 --window-y=0 --window-width=960 --window-height=1080 --zoom=0.8
今回感じた課題
-
AIによる推測への対応
ソースを基に試験項目表を作成するよう指示しても、Claude Codeによる推測で試験項目表が作成されている部分がありました(例:成功メッセージの抽出)。対策として、ソースだけを情報源とするようにmdファイルの内容を修正しました。修正内容についてもClaude Codeに相談すれば、要望に合わせて作成してくれます。
試験項目表作成時は、期待結果(メッセージ、遷移先URL、バリデーションエラー等)を必ず実装コード(server.js、js/*.js、*.html)から抽出し、推測や想定に基づく記載を避けること。
メッセージは `grep -r "メッセージ文言" webSample/` で確認し、完全一致するものを記載する。
-
自然言語指示の曖昧さ
「画面遷移して値を入力する」という指示に対して、画面遷移と入力を同時に行っており、入力欄が表示される前に値を入力しようとして失敗していたことがありました。対策としては待機時間を追加することで解消されましたが、段階を踏んで説明しないと伝わらない部分もあるということに気づき、プロンプトを工夫する必要性を感じました。
// 画面遷移を待機
await page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 10000 });
今回の取り組みで感じたこと
実現したいことを自然言語で指示すれば、複雑な処理でもコードに起こしてくれるClaude Codeはとても便利ですが、その一方でAIならではの課題もあると感じました。
1回の指示で完璧なものを作ろうとするのではなく、プロンプトを工夫してやりとりを重ね、少しずつ理想のものを作り上げていくという過程が必要だと思いました。
今回は入力チェック・登録・編集・削除といった基本的な処理のみを対象としたため、より複雑な処理の試験自動化についても実現できれば、試験における工数削減がより現実的になりそうだと感じました。


