コンテンツにスキップ

ステップアクションリファレンス

QA プランの各ステップは、http_request または browser の 2 つのアクションタイプのいずれかを実行します。AI エージェントが MCP ツールを通じて QA プランを構築する際に、これらのアクションを選択・設定します。このページでは、両方の完全な設定スキーマを説明します。

http_request アクションは HTTP リクエストを送信し、レスポンスを検証します。

フィールド必須説明
methodstringはいHTTP メソッド:GETPOSTPUTPATCHDELETE など。
urlstringはいリクエスト URL です。テンプレート変数をサポートします(例:{{base_url}}/api/users)。
headersRecord<string, string>いいえキーバリューペアのリクエストヘッダーです。値はテンプレート変数をサポートします。ランナーはここに書かれたヘッダーをそのまま送信し、Content-Type自動付与しません。詳細はヘッダーの取り扱いを参照。
bodyRequestBodyいいえリクエストボディです。下記の discriminated union で任意の Content-Type を表現できます。旧形式(プレーン object → JSON、文字列 → text)も後方互換でサポート。
authHttpAuthいいえ認証ヘルパー。指定すると対応する Authorization ヘッダーをランナーが組み立てます。詳細は認証を参照。
timeoutnumberいいえリクエストタイムアウト(ミリ秒)です。
pollPollConfigいいえ条件が満たされるまでエンドポイントをポーリングします。
response_body"auto" | "text" | "binary"いいえレスポンス body の扱い方。auto(既定)は Content-Type で判定。text は強制的に UTF-8 デコード、binary は強制的にバイナリ扱い。
max_response_body_sizenumberいいえレスポンス body から読み取る最大バイト数(既定 52428800 = 50MB)。超過時は body が打ち切られ body_truncated が立つ。

ランナーはプランに書かれたヘッダーをそのまま送信し、body が構造化されていても Content-Type自動付与しません。これは以下の QA ケースを表現可能にする意図的な設計です。

  • ネガティブテストContent-Type と body を意図的にミスマッチさせ、サーバーが 400 / 415 を返すことを検証
  • ベンダー固有 MIMEapplication/vnd.api+jsonapplication/ld+jsonapplication/problem+jsonapplication/cloudevents+json など
  • charset 付きapplication/json; charset=utf-8
  • Content-Type を意図的に省略 — ヘッダー欠落時のサーバーのデフォルト挙動を検証

multipart body の場合、body の boundary フィールドと Content-Type: multipart/form-data; boundary=<同じ値> ヘッダーを両方書く必要があります(自動同期されません)。

「ヘッダーをそのまま送る」原則の唯一の例外が auth フィールドです。auth を指定すると Authorization ヘッダーがランナーによって自動生成されます。さらに headers 側に明示的な Authorization も書かれている場合、両方の Authorization ヘッダーがそのままワイヤに乗ります(ランナーは重複排除しません)。競合が表に出ることでネガティブテストとして表現可能になります。

auth フィールドはリクエストの認証意図を構造化して指定します。認証情報内のテンプレート変数を展開し、対応する Authorization ヘッダーを組み立て、既存のマスキングルールで artifact 記録前にヘッダー値を秘匿します。headers に直書きするのに比べ、シークレットがプラン中で読みやすく、base64 化を自分で行う必要がない利点があります。

typeフィールド生成されるヘッダー
basicusername, passwordAuthorization: Basic <base64(username:password)> (RFC 7617)
bearertokenAuthorization: Bearer <token> (RFC 6750)

すべての認証情報フィールドは {{variable}} テンプレート展開をサポートするため、環境ファイルの secrets として管理できます。

Basic 認証:

{
"method": "GET",
"url": "{{api_base_url}}/admin",
"auth": {
"type": "basic",
"username": "{{admin_user}}",
"password": "{{admin_password}}"
}
}

Bearer トークン:

{
"method": "GET",
"url": "{{api_base_url}}/me",
"auth": { "type": "bearer", "token": "{{access_token}}" }
}

authheaders.Authorization が両方ある場合の挙動についてはヘッダーの取り扱いを参照。

bodytype による discriminated union です。実際にワイヤに乗せたい形式を明示します。

type用途必須フィールド
json通常の JSON(REST API の大半)。値が JSON.stringify されるvalue(任意の JSON 値)
formapplication/x-www-form-urlencoded のフォーム送信(ログインフォーム、OAuth トークン交換)fields: Record<string, string>
multipartmultipart/form-data(ファイルアップロード、HTML フォーム送信)fields?files?boundary?
text生テキスト body(XML/SOAP、プレーンテキスト webhook 等)value: string
binary生バイナリ(画像/PDF の PUT、application/octet-stream アップロード)path または content_base64 のいずれか1つ
graphqlGraphQL クエリエンベロープ(JSON の糖衣)query、任意で variables / operationName

discriminated union 以前に書かれたプランも引き続き動作します:プレーン object は { type: "json", value: <object> }、プレーン文字列は { type: "text", value: <string> } に正規化されます。新規プランは明示形式の使用を推奨します。

JSON POST:

{
"method": "POST",
"url": "{{api_base_url}}/users",
"headers": { "Content-Type": "application/json" },
"body": { "type": "json", "value": { "name": "Alice", "email": "alice@example.com" } }
}

Form-urlencoded:

{
"method": "POST",
"url": "{{api_base_url}}/login",
"headers": { "Content-Type": "application/x-www-form-urlencoded" },
"body": { "type": "form", "fields": { "username": "{{user}}", "password": "{{password}}" } }
}

Multipart ファイルアップロード:

{
"method": "POST",
"url": "{{api_base_url}}/upload",
"headers": { "Content-Type": "multipart/form-data; boundary=----aqua-b" },
"body": {
"type": "multipart",
"boundary": "----aqua-b",
"fields": { "title": "report" },
"files": [
{ "name": "file", "path": "./fixtures/sample.pdf", "filename": "sample.pdf", "content_type": "application/pdf" }
]
}
}

各ファイルエントリは path(cwd からの相対パス)、content(インライン UTF-8 テキスト)、content_base64(インラインバイナリ)のうちちょうど1つを指定します。

生テキスト(XML / SOAP):

{
"method": "POST",
"url": "{{api_base_url}}/soap",
"headers": { "Content-Type": "application/xml" },
"body": { "type": "text", "value": "<envelope>...</envelope>" }
}

生バイナリ(画像 PUT):

{
"method": "PUT",
"url": "{{api_base_url}}/avatar",
"headers": { "Content-Type": "image/png" },
"body": { "type": "binary", "path": "./fixtures/avatar.png" }
}

binary body は path または content_base64 のうちちょうど1つを指定します。

GraphQL:

{
"method": "POST",
"url": "{{api_base_url}}/graphql",
"headers": { "Content-Type": "application/json" },
"body": {
"type": "graphql",
"query": "query Q($id: ID!) { user(id: $id) { name } }",
"variables": { "id": "u_1" }
}
}

HTTP ドライバーはレスポンスの Content-Type ヘッダーで text/binary を判定します。text/*application/jsonapplication/xmlapplication/*+jsonapplication/*+xml は text 扱い、それ以外はバイナリ扱いです。

バイナリレスポンスの場合:

  • body は UTF-8 デコードされず、生バイトとして別の http_response_body アーティファクトに保存されます(Web UI からダウンロード可能。画像と PDF はプレビュー可能)
  • json_path アサーション、body_contains アサーション、extract は常に失敗 / 何も返しません — 代わりに headerbody_sizebody_hash アサーションを使用してください
  • レスポンスはストリーミングで読み込まれ、max_response_body_size でキャップされます。超過時は body が打ち切られ、アサーションは受信済みのバイトに対して評価されます

SHA-256 ハッシュとバイト数は text/binary を問わず常に計算されるため、body_sizebody_hash アサーションはどちらでも統一的に使えます。

一部の API エンドポイントではポーリングが必要です。条件が満たされるまでリクエストを繰り返します。poll を指定すると、until 条件が満たされるかタイムアウトに達するまで、一定間隔でリクエストが繰り返されます。

フィールド必須説明
untilobjectはいチェックする条件です。以下のサブフィールドのいずれかを指定する必要があります。
until.status_codenumberいいえレスポンスステータスコードがこの値と一致するまでポーリングします。
until.json_pathobjectいいえレスポンスボディの JSON パスが一致するまでポーリングします。path(文字列)と expected(任意)を含みます。
interval_msnumberはい各ポーリングリクエスト間の待機時間(ミリ秒)です。
timeout_msnumberはいポーリングが失敗とみなされるまでの最大合計時間(ミリ秒)です。

ポーリングの例 — 非同期ジョブの完了を待機:

{
"action": "http_request",
"config": {
"method": "GET",
"url": "{{api_base_url}}/jobs/{{job_id}}"
},
"poll": {
"until": {
"json_path": "$.status",
"equals": "completed"
},
"interval_ms": 2000,
"timeout_ms": 60000
}
}

extract フィールドは HTTP レスポンスから値をキャプチャし、後続のステップで使用できるようにします。各抽出は JSONPath 式を使用してレスポンスボディ内の値を特定します。抽出された値は {{variable_name}} でアクセス可能なテンプレート変数になります。

{
"extract": {
"user_id": "$.data.id",
"user_name": "$.data.name"
}
}

このステップの実行後、{{user_id}}{{user_name}} がすべての後続ステップで利用可能になります。

以下の例では、ユーザーを作成し、返された ID を抽出した後、ユーザーを取得して正しく作成されたことを検証します。

ステップ 1 — ユーザーの作成:

{
"step_key": "create_user",
"action": "http_request",
"config": {
"method": "POST",
"url": "{{api_base_url}}/users",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer {{auth_token}}"
},
"body": "{\"name\": \"Test User\", \"email\": \"test@example.com\"}"
},
"assertions": [
{ "type": "status_code", "expected": 201 },
{ "type": "json_path", "expression": "$.data.name", "equals": "Test User" }
],
"extract": {
"created_user_id": "$.data.id"
}
}

ステップ 2 — ユーザーの取得:

{
"step_key": "get_user",
"action": "http_request",
"depends_on": ["create_user"],
"config": {
"method": "GET",
"url": "{{api_base_url}}/users/{{created_user_id}}",
"headers": {
"Authorization": "Bearer {{auth_token}}"
}
},
"assertions": [
{ "type": "status_code", "expected": 200 },
{ "type": "json_path", "expression": "$.data.email", "equals": "test@example.com" }
]
}

ステップの condition フィールドは、変数の値に基づいてステップを実行するかどうかを制御します。条件が満たされない場合、ステップはスキップされます(depends_onrequires によるスキップと同じ動作です)。

条件チェックは depends_on のチェック後に評価されます。条件で参照する変数は通常、先行ステップの extract から取得します。

フィールド必須説明
typestringはい条件タイプ:"variable_equals" または "variable_not_equals" です。
variablestringはいチェックする変数名です。
valuestringはい比較する値です。

変数が指定された値と等しい場合のみステップを実行します。変数が未定義の場合、条件は満たされず、ステップはスキップされます。

{
"condition": {
"type": "variable_equals",
"variable": "user_role",
"value": "admin"
}
}

変数が指定された値と等しくない場合のみステップを実行します。変数が未定義の場合、条件は満たされ、ステップは実行されます。

{
"condition": {
"type": "variable_not_equals",
"variable": "payment_method",
"value": "free"
}
}

browser アクションは、Playwright を使用してヘッドレスブラウザを操作します。

フィールド必須説明
stepsBrowserStep[]はい実行するブラウザアクションの順序付き配列です。
timeout_msnumberいいえブラウザアクションシーケンス全体の最大時間(ミリ秒)です。

steps 配列の各エントリは、type フィールドとタイプ固有のパラメータを持つオブジェクトです。

タイプパラメータ説明
gotostring(URL)URL に遷移します。テンプレート変数をサポートします。
タイプパラメータ説明
clickstring(CSS セレクタ)要素をクリックします。
double_clickstring(CSS セレクタ)要素をダブルクリックします。
hoverstring(CSS セレクタ)要素にホバーします。
タイプパラメータ説明
type{ selector: string, text: string }入力フィールドにテキストを入力します。両方のフィールドでテンプレート変数をサポートします。
select_option{ selector: string, value: string }<select> 要素で値を指定してオプションを選択します。
checkstring(CSS セレクタ)チェックボックスをチェックします。
uncheckstring(CSS セレクタ)チェックボックスのチェックを外します。
press{ selector: string, key: string }要素にフォーカスした状態でキーボードキーを押します(例:EnterTab)。
focusstring(CSS セレクタ)要素にフォーカスします。
upload_file{ selector: string, path: string }ファイル入力要素にファイルをアップロードします。
タイプパラメータ説明
wait_for_selectorstring(CSS セレクタ)セレクタに一致する要素が DOM に表示されるまで待機します。
wait_for_urlstring(URL 部分文字列)ページの URL が指定した部分文字列を含むまで待機します。
タイプパラメータ説明
screenshotstring(名前)スクリーンショットを撮影し、指定した名前で保存します。
タイプパラメータ説明
set_headerRecord<string, string>後続のブラウザリクエストにカスタム HTTP ヘッダーを設定します。
タイプパラメータ説明
switch_to_framestring(CSS セレクタ)セレクタで指定された iframe に実行コンテキストを切り替えます。
switch_to_main_frametrueメインフレームに戻ります。

ブラウザコンテキストは単一のシナリオ内のすべてのステップで共有されます。これは以下を意味します。

  • ログインセッションはステップ間で維持されます。
  • Cookie と localStorage は保持されます。
  • ナビゲーション履歴は維持されます。

ブラウザの storageState(Cookie と localStorage)は、あるシナリオから次のシナリオに引き継がれます。これにより、初期のシナリオでログインを行い、認証フローを繰り返すことなく、以降のすべてのシナリオでそのセッションを利用できます。

以下の例では、ログインフローをテストし、ユーザーがダッシュボードに到達することを検証します。

ステップ 1 — ログイン:

{
"step_key": "login",
"action": "browser",
"config": {
"steps": [
{ "type": "goto", "url": "{{web_base_url}}/login" },
{ "type": "type", "selector": "#email", "text": "{{test_email}}" },
{ "type": "type", "selector": "#password", "text": "{{test_password}}" },
{ "type": "click", "selector": "button[type='submit']" },
{ "type": "wait_for_url", "url": "/dashboard" }
],
"timeout_ms": 15000
},
"assertions": [
{ "type": "url_contains", "expected": "/dashboard" },
{ "type": "element_visible", "selector": "[data-testid='welcome-message']" }
]
}

ステップ 2 — ダッシュボードの内容を検証:

{
"step_key": "verify_dashboard",
"action": "browser",
"depends_on": ["login"],
"config": {
"steps": [
{ "action": "wait_for_selector", "selector": "[data-testid='user-name']" }
]
},
"assertions": [
{ "type": "element_text", "selector": "[data-testid='user-name']", "expected": "Test User" },
{ "type": "element_visible", "selector": "[data-testid='recent-activity']" }
]
}