重要提示 - 路徑解析:此 Skill 可安裝於不同位置(外掛系統、手動安裝、全域或專案特定)。在執行任何命令之前,請先根據載入此 SKILL.md 檔案的位置確認 Skill 目錄,並在下方所有命令中使用該路徑。
重要提示 - 路徑解析:
此 Skill 可安裝於不同位置(外掛系統、手動安裝、全域或專案特定)。在執行任何命令之前,請先根據載入此 SKILL.md 檔案的位置確認 Skill 目錄,並在下方所有命令中使用該路徑。請將 $SKILL_DIR 替換為實際偵測到的路徑。
常見安裝路徑:
- 外掛系統:
<plugin-root>/skills/playwright-skill - 手動全域:
<agent-home>/skills/playwright-skill - 專案特定:
<project>/.agent/skills/playwright-skill
Playwright 瀏覽器自動化
通用型瀏覽器自動化 Skill。我會針對你要求的任何自動化任務撰寫客製化的 Playwright 程式碼,並透過通用執行器(universal executor)執行。
關鍵工作流程 - 請依序執行以下步驟:
-
自動偵測開發伺服器(Dev Server) - 進行 localhost 測試時,務必先執行伺服器偵測:
cd $SKILL_DIR && node -e "require('./lib/helpers').detectDevServers().then(servers => console.log(JSON.stringify(servers)))"- 若找到 1 個伺服器:自動使用該伺服器並通知使用者
- 若找到多個伺服器:詢問使用者要測試哪一個
- 若未找到伺服器:要求提供 URL,或詢問是否需要協助啟動開發伺服器
-
將腳本寫入 /tmp - 切勿將測試檔案寫入 Skill 目錄;請一律使用
/tmp/playwright-test-*.js -
預設使用可視瀏覽器 - 除非使用者特別要求無頭模式(headless mode),否則一律使用
headless: false -
URL 參數化 - 一律將 URL 設定為可透過環境變數或腳本頂端的常數進行組態配置
運作方式
- 你描述想要測試或自動化的內容
- 我自動偵測執行中的開發伺服器(若測試外部網站則詢問 URL)
- 我在
/tmp/playwright-test-*.js中撰寫客製化的 Playwright 程式碼(不會弄亂你的專案) - 我透過以下命令執行:
cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js - 結果即時顯示,並開啟瀏覽器視窗方便除錯
- 測試檔案會由作業系統自動清理
/tmp
安裝與設定(首次使用)
cd $SKILL_DIR
npm run setup
這會安裝 Playwright 與 Chromium 瀏覽器。只需執行一次。
執行模式
步驟 1:偵測開發伺服器(用於 localhost 測試)
cd $SKILL_DIR && node -e "require('./lib/helpers').detectDevServers().then(s => console.log(JSON.stringify(s)))"
步驟 2:將帶有 URL 參數的測試腳本寫入 /tmp
// /tmp/playwright-test-page.js
const { chromium } = require('playwright');
// 參數化 URL(已偵測或由使用者提供)
const TARGET_URL = 'http://localhost:3001'; // <-- 自動偵測或來自使用者
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(TARGET_URL);
console.log('Page loaded:', await page.title());
await page.screenshot({ path: '/tmp/screenshot.png', fullPage: true });
console.log('📸 Screenshot saved to /tmp/screenshot.png');
await browser.close();
})();
步驟 3:從 Skill 目錄執行
cd $SKILL_DIR && node run.js /tmp/playwright-test-page.js
常見模式
測試頁面(多種 Viewport 尺寸)
// /tmp/playwright-test-responsive.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自動偵測
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 100 });
const page = await browser.newPage();
// 桌面端測試
await page.setViewportSize({ width: 1920, height: 1080 });
await page.goto(TARGET_URL);
console.log('Desktop - Title:', await page.title());
await page.screenshot({ path: '/tmp/desktop.png', fullPage: true });
// 行動端測試
await page.setViewportSize({ width: 375, height: 667 });
await page.screenshot({ path: '/tmp/mobile.png', fullPage: true });
await browser.close();
})();
測試登入流程
// /tmp/playwright-test-login.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自動偵測
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(`${TARGET_URL}/login`);
await page.fill('input[name="email"]', 'test@example.com');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
// 等待轉址
await page.waitForURL('**/dashboard');
console.log('✅ Login successful, redirected to dashboard');
await browser.close();
})();
填寫並提交表單
// /tmp/playwright-test-form.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自動偵測
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 50 });
const page = await browser.newPage();
await page.goto(`${TARGET_URL}/contact`);
await page.fill('input[name="name"]', 'John Doe');
await page.fill('input[name="email"]', 'john@example.com');
await page.fill('textarea[name="message"]', 'Test message');
await page.click('button[type="submit"]');
// 驗證提交結果
await page.waitForSelector('.success-message');
console.log('✅ Form submitted successfully');
await browser.close();
})();
檢查失效連結 (Broken Links)
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('http://localhost:3000');
const links = await page.locator('a[href^="http"]').all();
const results = { working: 0, broken: [] };
for (const link of links) {
const href = await link.getAttribute('href');
try {
const response = await page.request.head(href);
if (response.ok()) {
results.working++;
} else {
results.broken.push({ url: href, status: response.status() });
}
} catch (e) {
results.broken.push({ url: href, error: e.message });
}
}
console.log(`✅ Working links: ${results.working}`);
console.log(`❌ Broken links:`, results.broken);
await browser.close();
})();
擷取螢幕截圖(含錯誤處理)
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
try {
await page.goto('http://localhost:3000', {
waitUntil: 'networkidle',
timeout: 10000,
});
await page.screenshot({
path: '/tmp/screenshot.png',
fullPage: true,
});
console.log('📸 Screenshot saved to /tmp/screenshot.png');
} catch (error) {
console.error('❌ Error:', error.message);
} finally {
await browser.close();
}
})();
測試響應式設計 (Responsive Design)
// /tmp/playwright-test-responsive-full.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自動偵測
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
const viewports = [
{ name: 'Desktop', width: 1920, height: 1080 },
{ name: 'Tablet', width: 768, height: 1024 },
{ name: 'Mobile', width: 375, height: 667 },
];
for (const viewport of viewports) {
console.log(
`Testing ${viewport.name} (${viewport.width}x${viewport.height})`,
);
await page.setViewportSize({
width: viewport.width,
height: viewport.height,
});
await page.goto(TARGET_URL);
await page.waitForTimeout(1000);
await page.screenshot({
path: `/tmp/${viewport.name.toLowerCase()}.png`,
fullPage: true,
});
}
console.log('✅ All viewports tested');
await browser.close();
})();
行內執行(簡單任務)
對於快速的一次性任務,你可以直接使用行內命令執行程式碼,無需建立檔案:
# 快速擷取螢幕截圖
cd $SKILL_DIR && node run.js "
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('http://localhost:3001');
await page.screenshot({ path: '/tmp/quick-screenshot.png', fullPage: true });
console.log('Screenshot saved');
await browser.close();
"
何時使用行內執行 vs 檔案:
- 行內執行:快速一次性任務(如拍照截圖、檢查元素是否存在、取得頁面標題)
- 檔案形式:複雜測試、響應式設計檢查,或任何使用者可能需要重新執行的內容
可用輔助函式 (Helpers)
lib/helpers.js 提供可選的實用工具函式:
const helpers = require('./lib/helpers');
// 偵測執行中的開發伺服器(至關重要 - 請最先使用此功能!)
const servers = await helpers.detectDevServers();
console.log('Found servers:', servers);
// 帶有重試機制的安全點擊
await helpers.safeClick(page, 'button.submit', { retries: 3 });
// 帶有清空輸入框功能的安全輸入
await helpers.safeType(page, '#username', 'testuser');
// 擷取帶有時間戳記的截圖
await helpers.takeScreenshot(page, 'test-result');
// 處理 Cookie 彈窗橫幅
await helpers.handleCookieBanner(page);
// 擷取表格資料
const data = await helpers.extractTableData(page, 'table.results');
完整清單請參閱 lib/helpers.js。
客製化 HTTP 標頭 (Custom HTTP Headers)
可透過環境變數為所有 HTTP 請求設定客製化 Header。適用於:
- 標示傳送至後端的自動化流量
- 取得適合 LLM 處理的回應(例如純文字錯誤而非帶有樣式的 HTML)
- 在全域範圍加入身分驗證 Token
設定方式
單一標頭(常見用法):
PW_HEADER_NAME=X-Automated-By PW_HEADER_VALUE=playwright-skill \
cd $SKILL_DIR && node run.js /tmp/my-script.js
多個標頭(JSON 格式):
PW_EXTRA_HEADERS='{"X-Automated-By":"playwright-skill","X-Debug":"true"}' \
cd $SKILL_DIR && node run.js /tmp/my-script.js
運作原理
使用 helpers.createContext() 時會自動套用標頭:
const context = await helpers.createContext(browser);
const page = await context.newPage();
// 此頁面的所有請求都會包含你自訂的 Headers
若腳本直接使用 Playwright 原生 API,請使用注入的 getContextOptionsWithHeaders():
const context = await browser.newContext(
getContextOptionsWithHeaders({ viewport: { width: 1920, height: 1080 } }),
);
進階用法
關於完整的 Playwright API 文件,請參閱 API_REFERENCE.md:
- 選擇器與定位器(Selectors & Locators)的最佳實踐
- 網路攔截與 API 模擬 (Mocking)
- 身分驗證與 Session 管理
- 視覺回歸測試 (Visual regression testing)
- 行動裝置模擬
- 效能測試
- 除錯技巧
- CI/CD 整合
實用技巧
- 極度重要:最先偵測伺服器 - 為 localhost 測試編寫測試程式碼前,務必先執行
detectDevServers() - 自訂標頭 - 使用
PW_HEADER_NAME/PW_HEADER_VALUE環境變數來標示傳送至後端的自動化流量 - 使用 /tmp 存放測試檔案 - 將檔案寫入
/tmp/playwright-test-*.js,切勿寫入 Skill 目錄或使用者的專案目錄 - URL 參數化 - 將偵測到或由使用者提供的 URL 放在每個腳本頂端的
TARGET_URL常數中 - 預設:開啟可視瀏覽器 - 除非使用者明確要求無頭模式,否則一律使用
headless: false - 無頭模式 - 僅在使用者明確要求「無頭 (headless)」或「背景 (background)」執行時使用
headless: true - 放慢執行速度: 使用
slowMo: 100讓操作過程可視化且更容易追蹤 - 等待策略:




