local-testing について
local-testingは、macOS上のローカルアプリやボットをテストするスキルです。CDP経由のagent-browserでElectronやWebアプリを自動化し、osascriptでネイティブアプリを操作するほか、環境管理、チャネル別資料、スクリプト、検証手順を提供します。
主な機能
- 01CDP経由でElectronとWebアプリを自動化
- 02osascriptでネイティブアプリを操作
- 03チャネル別のボットテスト資料
- 04Electronの起動管理と録画スクリプト
- 05スクリーンショットとUI検証に対応
活用シーン
- 01UIを通じてElectronアプリをテスト
- 02デスクトップボットへテストメッセージを送信
- 03アプリの動作確認用スクリーンショットを取得
- 04iMessage bridgeの回帰チェックを実行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lobehub/ lobehub --skill local-testingインストール後、Claude Code で/local-testingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
bot/capture-app-window.shosascript-common.mdbot/discord/index.mdtest-discord-bot.shbot/imessage/index.mdsend-imessage-test.shtest-imessage-bridge.shbot/lark/index.mdtest-lark-bot.shbot/qq/index.mdtest-qq-bot.shbot/slack/index.mdtest-slack-bot.shbot/telegram/index.mdtest-telegram-bot.shbot/wechat/index.mdtest-wechat-bot.shreferences/agent-browser-login.mdagent-gateway.mdrecord-app-screen.mdscripts/electron-dev.shscripts/agent-gateway/analyze-events.tsanalyze.mjsprobe-dump.jsprobe-dump.tsprobe-events.tsprobe.jsrun.tstab-switch.jstypes.ts詳細
ローカルアプリとボットのテスト
macOS でローカルテストを行う方法は 2 つあります。
| 方法 | ツール | 最適な用途 |
|---|---|---|
| agent-browser + CDP | agent-browser CLI | Electron アプリ、Web アプリ(DOM アクセス、JS 評価) |
| osascript (AppleScript) | osascript -e | macOS ネイティブアプリ(WeChat、Discord、Telegram、Slack) |
パート 1:agent-browser(Electron / Web アプリ)
agent-browser を使用して、Chrome DevTools Protocol 経由で Chromium ベースのアプリを自動化します。
npm i -g agent-browser、brew install agent-browser、または cargo install agent-browser でインストールします。agent-browser install を実行して Chrome をダウンロードします。更新するには agent-browser upgrade を実行します。
基本的なワークフロー
ブラウザーの自動化は、すべて次のパターンに従います。
- 移動:
agent-browser open <url> - スナップショット:
agent-browser snapshot -i(@e1、@e2などの要素参照を取得) - 操作:参照を使ってクリック、入力、選択を行う
- 再スナップショット:ページ遷移後や DOM 変更後に、新しい参照を取得する
agent-browser open https://example.com/form
agent-browser snapshot -i
# Output: @e1 [input type="email"], @e2 [input type="password"], @e3 [button] "Submit"
agent-browser fill @e1 "[email protected]"
agent-browser fill @e2 "password123"
agent-browser click @e3
agent-browser wait --load networkidle
agent-browser snapshot -i # Check result
コマンドの連結
# Chain open + wait + snapshot in one call
agent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser snapshot -i
中間出力を読み取る必要がない場合は、&& を使用します。先に出力を解析する必要がある場合(例:スナップショットから参照を見つけてから操作する場合)は、コマンドを個別に実行します。
基本的なコマンド
# Navigation
agent-browser open <url> # Navigate (aliases: goto, navigate)
agent-browser close # Close browser
agent-browser close --all # Close all active sessions
# Snapshot
agent-browser snapshot -i # Interactive elements with refs (recommended)
agent-browser snapshot -s "#selector" # Scope to CSS selector
# Interaction (use @refs from snapshot)
agent-browser click @e1 # Click element
agent-browser click @e1 --new-tab # Click and open in new tab
agent-browser fill @e2 "text" # Clear and type text
agent-browser type @e2 "text" # Type without clearing
agent-browser select @e1 "option" # Select dropdown option
agent-browser check @e1 # Check checkbox
agent-browser press Enter # Press key
agent-browser keyboard type "text" # Type at current focus (no selector)
agent-browser keyboard inserttext "text" # Insert without key events
agent-browser scroll down 500 # Scroll page
agent-browser scroll down 500 --selector "div.content" # Scroll within container
# Get information
agent-browser get text @e1 # Get element text
agent-browser get url # Get current URL
agent-browser get title # Get page title
agent-browser get cdp-url # Get CDP WebSocket URL
# Wait
agent-browser wait @e1 # Wait for element
agent-browser wait --load networkidle # Wait for network idle
agent-browser wait --url "**/page" # Wait for URL pattern
agent-browser wait 2000 # Wait milliseconds
agent-browser wait --text "Welcome" # Wait for text to appear
agent-browser wait --fn "!document.body.innerText.includes('Loading...')" # Wait for text to disappear
agent-browser wait "#spinner" --state hidden # Wait for element to disappear
# Downloads
agent-browser download @e1 ./file.pdf # Click element to trigger download
agent-browser wait --download ./output.zip # Wait for any download to complete
# Network
agent-browser network requests # Inspect tracked requests
agent-browser network requests --type xhr,fetch # Filter by resource type
agent-browser network requests --method POST # Filter by HTTP method
agent-browser network route "**/api/*" --abort # Block matching requests
agent-browser network har start # Start HAR recording
agent-browser network har stop ./capture.har # Stop and save HAR file
# Viewport & Device Emulation
agent-browser set viewport 1920 1080 # Set viewport size (default: 1280x720)
agent-browser set viewport 1920 1080 2 # 2x retina
agent-browser set device "iPhone 14" # Emulate device (viewport + user agent)
# Capture
agent-browser screenshot # Screenshot to temp dir
agent-browser screenshot --full # Full page screenshot
agent-browser screenshot --annotate # Annotated screenshot with numbered element labels
agent-browser pdf output.pdf # Save as PDF
# Clipboard
agent-browser clipboard read # Read text from clipboard
agent-browser clipboard write "text" # Write text to clipboard
agent-browser clipboard copy # Copy current selection
agent-browser clipboard paste # Paste from clipboard
# Dialogs (alert, confirm, prompt, beforeunload)
agent-browser dialog accept # Accept dialog
agent-browser dialog accept "input" # Accept prompt dialog with text
agent-browser dialog dismiss # Dismiss/cancel dialog
agent-browser dialog status # Check if dialog is open
# Diff (compare page states)
agent-browser diff snapshot # Compare current vs last snapshot
agent-browser diff screenshot --baseline before.png # Visual pixel diff
agent-browser diff url <url1> <url2> # Compare two pages
# Streaming
agent-browser stream enable # Start WebSocket streaming
agent-browser stream status # Inspect streaming state
agent-browser stream disable # Stop streaming
一括実行
echo '[
["open", "https://example.com"],
["snapshot", "-i"],
["click", "@e1"],
["screenshot", "result.png"]
]' | agent-browser batch --json
認証
# Option 1: Auth vault (credentials stored encrypted)
echo "$PASSWORD" | agent-browser auth save myapp --url https://app.example.com/login --username user --password-stdin
agent-browser auth login myapp
# Option 2: Session name (auto-save/restore cookies + localStorage)
agent-browser --session-name myapp open https://app.example.com/login
agent-browser close # State auto-saved
agent-browser --session-name myapp open https://app.example.com/dashboard # Auto-restored
# Option 3: Persistent profile
agent-browser --profile ~/.myapp open https://app.example.com/login
# Option 4: State file
agent-browser state save auth.json
agent-browser state load auth.json
LobeHub 開発サーバー — better-auth Cookie の注入
macOS で agent-browser --headed を実行すると、画面外に Chromium ウィンドウが作成され、手動ログインが妨げられることがあります。ローカルの LobeHub 開発サーバー(例:localhost:3011)の場合は、ユーザー自身の Chrome DevTools の Network request から better-auth.session_token Cookie をコピーし、state load で読み込みます。手順の詳細は references/agent-browser-login.md を参照してください。
セマンティックロケーター(参照の代替)
agent-browser find text "Sign In" click
agent-browser find label "Email" fill "[email protected]"
agent-browser find role button click --name "Submit"
agent-browser find placeholder "Search" type "query"
agent-browser find testid "submit-btn" click
JavaScript 評価(eval)
# Simple expressions
agent-browser eval 'document.title'
# Complex JS: use --stdin with heredoc (RECOMMENDED)
agent-browser eval --stdin << 'EVALEOF'
JSON.stringify(
Array.from(document.querySelectorAll("img"))
.filter(i => !i.alt)
.map(i => ({ src: i.src.split("/").pop(), width: i.width }))
)
EVALEOF
# Base64 encoding (avoids all shell escaping issues)
agent-browser eval -b "$(echo -n 'document.title' | base64)"
参照のライフサイクル
参照(@e1、@e2 など)はページが変わると無効になります。ページ遷移を伴うリンクやボタンのクリック、フォームの送信、動的コンテンツの読み込み後は、必ずスナップショットを再取得してください。
注釈付きスクリーンショット(ビジョンモード)
agent-browser screenshot --annotate
# Output includes the image path and a legend:
# [1] @e1 button "Submit"
# [2] @e2 link "Home"
agent-browser click @e2 # Click using ref from annotated screenshot
並列セッション
agent-browser --session site1 open https://site-a.com
agent-browser --session site2 open https://site-b.com
agent-browser session list
既存の Chrome に接続
agent-browser --auto-connect snapshot # Auto-discover running Chrome
agent-browser --cdp 9222 snapshot # Explicit CDP port
iOS シミュレーター(モバイル Safari)
agent-browser device list
agent-browser -p ios --device "iPhone 16 Pro" open https://example.com
agent-browser -p ios snapshot -i
agent-browser -p ios tap @e1
agent-browser -p ios swipe up
agent-browser -p ios screenshot mobile.png
agent-browser -p ios close
可観測性ダッシュボード
agent-browser dashboard install
agent-browser dashboard start # Background server on port 4848
agent-browser dashboard stop
クラウドプロバイダー
-p <provider> を使用すると、クラウドブラウザーに対して実行できます:agentcore、browserbase、browserless、browseruse、kernel。
ブラウザーエンジンの選択
agent-browser --engine lightpanda open example.com # 10x faster, 10x less memory
Electron(LobeHub デスクトップ)
セットアップ/終了処理
electron-dev.sh スクリプトを使用して Electron の開発環境を管理します。プロセスのライフサイクルを管理し、SPA の準備完了を待ち、すべての子プロセス(main + helpers + vite)を確実に終了します。
SCRIPT=".agents/skills/local-testing/scripts/electron-dev.sh"
# Start Electron dev with CDP (idempotent — skips if already running)
$SCRIPT start
# Check if Electron is running and CDP is reachable
$SCRIPT status
# Kill all Electron-related processes (main + helper + vite)
$SCRIPT stop
# Force fresh restart
$SCRIPT restart
start が成功したら、agent-browser --cdp 9222 snapshot -i で接続します。
テストが終わったら、必ず $SCRIPT stop を実行してください — pkill -f "Electron" だけでは、すべてのヘルパープロセスを終了できません。
環境変数
| 変数 | デフォルト | 説明 |
|---|---|---|
CDP_PORT | 9222 | Chrome DevTools Protocol ポート |
ELECTRON_LOG | /tmp/electron-dev.log | Electron プロセスのログ |
ELECTRON_WAIT_S | 60 | Electron プロセスの待機時間(最大秒数) |
RENDERER_WAIT_S | 60 | SPA の読み込み待機時間(最大秒数) |
LobeHub 固有のパターン
Zustand ストアの状態を取得
agent-browser --cdp 9222 eval --stdin << 'EVALEOF'
(function() {
var chat = window.__LOBE_STORES.chat();
var ops = Object.values(chat.operations);
return JSON.stringify({
ops: ops.map(function(o) { return { type: o.type, status: o.status }; }),
activeAgent: chat.activeAgentId,
activeTopic: chat.activeTopicId,
});
})()
EVALEOF
チャット入力欄を見つけて使用
# The chat input is contenteditable — must use -C flag
agent-browser --cdp 9222 snapshot -i -C 2>&1 | grep "editable"
agent-browser --cdp 9222 click @e48
agent-browser --cdp 9222 type @e48 "Hello world"
agent-browser --cdp 9222 press Enter
エージェントの完了を待つ
agent-browser --cdp 9222 eval --stdin << 'EVALEOF'
(function() {
var chat = window.__LOBE_STORES.chat();
var ops = Object.values(chat.operations);
var running = ops.filter(function(o) { return o.status === 'running'; });
return running.length === 0 ? 'done' : 'running: ' + running.length;
})()
EVALEOF
エラーインターセプターをインストール
agent-browser --cdp 9222 eval --stdin << 'EVALEOF'
(function() {
window.__CAPTURED_ERRORS = [];
var orig = console.error;
console.error = function() {
var msg = Array.from(arguments).map(function(a) {
if (a instanceof Error) return a.message;
return typeof a === 'object' ? JSON.stringify(a) : String(a);
}).join(' ');
window.__CAPTURED_ERRORS.push(msg);
orig.apply(console, arguments);
};
return 'installed';
})()
EVALEOF
# Later, check captured errors:
agent-browser --cdp 9222 eval "JSON.stringify(window.__CAPTURED_ERRORS)"
Chrome / Web アプリ
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--remote-debugging-port=9222 \
--user-data-dir=/tmp/chrome-test-profile \
"<URL>" &
sleep 5
agent-browser --cdp 9222 snapshot -i
# Or auto-discover running Chrome with remote debugging
agent-browser --auto-connect snapshot -i
Part 2:osascript(macOS ネイティブアプリのボットテスト)
osascript 経由で AppleScript を使用し、macOS のネイティブデスクトップアプリを操作してボットをテストします。macOS のアクセシビリティに対応しているアプリならどれでも動作し、CDP や Chromium は必要ありません。
どのプラットフォームでも、手順は同じです。
- アクティブ化する(
tell application "X" to activate) - 移動する(クイックスイッチャーの
Cmd+Kまたは検索のCmd+F) - メッセージを送信する(クリップボードから貼り付けて
Cmd+Vを押し、Enter を押す) - ボットの応答を待つ
- スクリーンショットで確認する(
screencaptureとReadツールを使用)
プラットフォーム別リファレンス
対象プラットフォームのファイルを選択してください。それぞれのファイルには、そのアプリに特化したアクティブ化、移動、メッセージ送信、確認のスニペットが含まれています。
各チャンネルには bot/<channel>/ 以下に専用のフォルダーがあります。このフォルダーには、そのアプリに特化したアクティブ化、移動、メッセージ送信、確認のスニペットを含む index.md と、テストスクリプトが格納されています。
| プラットフォーム | リファレンス | クイックスイッチャー |
|---|---|---|
| Discord | bot/discord/index.md | Cmd+K |
| Slack | bot/slack/index.md | Cmd+K |
| Telegram | bot/telegram/index.md | Cmd+F |
| WeChat / 微信 | bot/wechat/index.md | Cmd+F |
| Lark / 飞书 | bot/lark/index.md | Cmd+K |
| bot/qq/index.md | Cmd+F |
共有の osascript パターン(アクティブ化、入力、貼り付け、スクリーンショット、アクセシビリティ情報の読み取り、共通のワークフローテンプレート、注意点)については、bot/osascript-common.md を参照してください。osascript による自動化が初めての場合は、最初にこちらをお読みください。
ブリッジベースのチャンネル(ネイティブアプリなし)
一部のチャンネルには、osascript で操作できるネイティブアプリがなく、デスクトップアプリ内のローカルブリッジを介して接続します。これらのテストには osascript ではなく、agent-browser(IPC + UI)とブリッジ独自の HTTP/REST エンドポイントを使用します。
| チャンネル | リファレンス | 操作対象 |
|---|---|---|
| iMessage | bot/imessage/index.md | imessageBridge.* IPC + ローカルブリッジ + BlueBubbles REST |
iMessage 用のワンショット回帰テストスクリプトについては、下記の test-imessage-bridge.sh を参照してください。
スクリプト
.agents/skills/local-testing/scripts/ にあるアプリ/録画スクリプト:
| スクリプト | 用途 |
|---|---|
electron-dev.sh | Electron 開発環境を管理(起動/停止/状態確認/再起動) |
record-electron-demo.sh | ffmpeg で Electron アプリのデモを録画 |
record-app-screen.sh | アプリ画面を録画(動画+スクリーンショット、開始/停止) |
ボットスクリプトは .agents/skills/local-testing/bot/ 以下にあり、チャンネルごとにフォルダーが分かれています(各チャンネルの index.md と同じ場所)。共通の capture-app-window.sh は bot/ のルートにあります:
| スクリプト | 用途 |
|---|---|
capture-app-window.sh | 特定のアプリウィンドウのスクリーンショットを撮影(ボットテストで使用) |
discord/test-discord-bot.sh | osascript で Discord ボットにメッセージを送信 |
slack/test-slack-bot.sh | osascript で Slack ボットにメッセージを送信 |
telegram/test-telegram-bot.sh | osascript で Telegram ボットにメッセージを送信 |
wechat/test-wechat-bot.sh | osascript で WeChat ボットにメッセージを送信 |
lark/test-lark-bot.sh | osascript で Lark / 飞书 ボットにメッセージを送信 |
qq/test-qq-bot.sh | osascript で QQ ボットにメッセージを送信 |
imessage/test-imessage-bridge.sh | iMessage BlueBubbles ブリッジの回帰テスト(IPC + HTTP) |
imessage/send-imessage-test.sh | 実際の iMessage を1件送信(デスクトップ → BB → iMessage)し、送信を確認 |
ウィンドウのスクリーンショットユーティリティ
capture-app-window.sh は screencapture -l <windowID> を使って、特定のアプリウィンドウのスクリーンショットを撮影します。Swift + CGWindowList を使い、プロセス名からウィンドウを特定するため、ウィンドウが外部モニター上にある場合や、ほかのウィンドウの背後にある場合でも、正しくスクリーンショットを撮影できます。
# Standalone usage
./.agents/skills/local-testing/bot/capture-app-window.sh "Discord" /tmp/discord.png
./.agents/skills/local-testing/bot/capture-app-window.sh "Slack" /tmp/slack.png
./.agents/skills/local-testing/bot/capture-app-window.sh "WeChat" /tmp/wechat.png
すべてのボットテストスクリプトは、スクリーンショットの撮影にこのユーティリティを自動的に使用します。
ボットテストスクリプト
すべてのボットテストスクリプトは、共通のインターフェイスを使用します:
./scripts/test-<platform>-bot.sh <channel_or_contact> <message> [wait_seconds] [screenshot_path]
例:
# Discord — test a bot in #bot-testing channel
./.agents/skills/local-testing/bot/discord/test-discord-bot.sh "bot-testing" "!ping"
./.agents/skills/local-testing/bot/discord/test-discord-bot.sh "bot-testing" "/ask Tell me a joke" 30
# Slack — test a bot in #bot-testing channel
./.agents/skills/local-testing/bot/slack/test-slack-bot.sh "bot-testing" "@mybot hello"
./.agents/skills/local-testing/bot/slack/test-slack-bot.sh "bot-testing" "/ask What is 2+2?" 20
# Telegram — test a bot by username
./.agents/skills/local-testing/bot/telegram/test-telegram-bot.sh "MyTestBot" "/start"
./.agents/skills/local-testing/bot/telegram/test-telegram-bot.sh "GPTBot" "Hello" 60
# WeChat — test a bot or send to a contact
./.agents/skills/local-testing/bot/wechat/test-wechat-bot.sh "文件传输助手" "test message" 5
./.agents/skills/local-testing/bot/wechat/test-wechat-bot.sh "MyBot" "Tell me a joke" 30
# Lark/飞书 — test a bot in a group chat
./.agents/skills/local-testing/bot/lark/test-lark-bot.sh "bot-testing" "@MyBot hello"
./.agents/skills/local-testing/bot/lark/test-lark-bot.sh "bot-testing" "Help me with this" 30
# QQ — test a bot in a group or direct chat
./.agents/skills/local-testing/bot/qq/test-qq-bot.sh "bot-testing" "Hello bot" 15
./.agents/skills/local-testing/bot/qq/test-qq-bot.sh "MyBot" "/help" 10
各スクリプトは、アプリをアクティブにし、チャンネル/連絡先に移動して、クリップボード経由でメッセージを貼り付け、送信し、待機してからスクリーンショットを撮影します。目視で確認するには、スクリーンショットに対して Read ツールを使用してください。
iMessage ブリッジの回帰テストスクリプト
test-imessage-bridge.sh は osascript ボットのインターフェイスには従いません。Desktop ブリッジの IPC + HTTP 層を操作して結果を検証し、その後、自動的にクリーンアップします。BlueBubbles が起動しており、Electron が CDP とともに稼働している必要があります。
./.agents/skills/local-testing/bot/imessage/test-imessage-bridge.sh '<bluebubbles_password>' [bb_url] [cdp_port]
# defaults: bb_url=http://127.0.0.1:1234 cdp_port=9222 — exit 0 = all green
接続/設定フロー(testConfig の成功パスと拒否パス、初回の upsertConfig 保存、ブリッジの稼働と webhook の登録、ローカルサーバーのシークレット適用)を保護します。手動での UI 操作フローと既知のバグについては、bot/imessage/index.md を参照してください。
画面録画
record-app-screen.sh を使って、自動デモを録画できます(開始/停止のライフサイクル、CDP スクリーンショット + ffmpeg による組み立て)。詳しくは references/record-app-screen.md を参照してください。
./.agents/skills/local-testing/scripts/electron-dev.sh start
./.agents/skills/local-testing/scripts/record-app-screen.sh start my-demo
# ... run automation ...
./.agents/skills/local-testing/scripts/record-app-screen.sh stop
出力先は .records/ ディレクトリ(gitignore 対象)です:<name>.mp4(動画)と <name>/(3秒ごとのスクリーンショット)。
注意点
agent-browser
- デーモンが応答しなくなることがあります — コマンドがハングした場合は、
agent-browser close --allまたはpkill -f agent-browserを実行してリセットしてください - HMR によってすべてが無効になります — コードを変更すると、参照が壊れます。スナップショットを再取得するか、再起動してください
snapshot -iでは contenteditable が見つかりません — リッチテキストエディターにはsnapshot -i -Cを使用してくださいfillは contenteditable では機能しません — チャットの入力欄にはtypeを使用してください- スクリーンショットは
~/.agent-browser/tmp/screenshots/に保存されます —Readツールで読み込んでください - ダイアログがすべてのコマンドをブロックします — コマンドがタイムアウトした場合は、
agent-browser dialog statusを確認してください - デフォルトのタイムアウトは 25s です —
AGENT_BROWSER_DEFAULT_TIMEOUT(ms)で上書きするか、明示的な待機を使用してください - シェルのクォートによって eval が壊れることがあります — 複雑な JS には
eval --stdin <<'EVALEOF'を使用してください
Electron固有
- クリーンアップには必ず
electron-dev.sh stopを使用してください —pkill -f "Electron"ではメインプロセスしか終了せず、ヘルパープロセス(GPU、レンダラー、ネットワーク)が残ります。このスクリプトは、プロジェクトの electron バイナリパスと PID を照合して、すべてのプロセスを検出して終了します。 npx electron-vite devはapps/desktop/から実行する必要があります — プロジェクトのルートから実行すると、エラーが表示されずに失敗します。electron-dev.shスクリプトが自動的に処理します。- 読み込み後に Electron ウィンドウのサイズを変更しないでください — サイズを変更すると、SPA が完全に再読み込みされます
- ストアは
window.__ZUSTAND_STORES__ではなくwindow.__LOBE_STORESにあります
osascript
osascript の注意事項(アクセシビリティ権限、keystroke の非 ASCII 文字に関する問題、ロケール固有のアプリ名、レート制限など)の全一覧は、bot/osascript-common.md を参照してください。