desktop-workflow-to-playwright について
desktop-workflow-to-playwrightは、文書化されたデスクトップワークフローをPlaywrightのエンドツーエンドテストプロジェクトに変換します。QA自動化向けに、テスト生成、認証の土台、Vercelプレビュー用のGitHub Actions設定を行います。
主な機能
- 01デスクトップワークフロー文書の解析
- 02Playwrightワークフローテストの生成
- 03認証セットアップの土台作成
- 04プレビュー向けGitHub Actions設定
- 05タスクリストによる進捗管理
活用シーン
- 01ワークフロー文書からテストを作成
- 02デスクトップE2Eテストプロジェクトの作成
- 03Vercelプレビュー向けテストの準備
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ neonwatty/ qa-skills --skill desktop-workflow-to-playwrightインストール後、Claude Code で/desktop-workflow-to-playwrightを入力して読み込まれたか確認します。
詳細
デスクトップワークフローからPlaywrightへの変換
あなたは、人が読めるデスクトップワークフローのドキュメントを、自己完結型のPlaywrightテストプロジェクトに変換する、経験豊富なQA自動化エンジニアです。/workflows/desktop-workflows.mdからワークフローを読み取り、すべての手順を慣用的なPlaywrightコードに変換して、認証の足場、CI設定、Vercelデプロイ保護ヘッダーを含む、完全に機能するテストプロジェクトをe2e/desktop/に作成してください。
生成されるすべてのテストは、cd e2e/desktop && npm ci && npx playwright testを実行すれば、すぐに実行できる必要があります。
タスクリストとの連携
タスクリストは、エージェントの進捗を追跡し、ユーザーに状況を伝え、中断後のセッション復旧を可能にし、レビューの反復を記録し、解析・生成・承認された内容の監査証跡として機能します。
タスク階層
このスキルを実行するたびに、次のタスクツリーが作成されます。タスクは順番に完了します。
[Main Task] "Convert: Desktop Workflows to Playwright"
+-- [Parse Task] "Parse: desktop-workflows.md"
+-- [Check Task] "Check: Existing e2e/desktop/ project"
+-- [Selector Task] "Selectors: Find for all workflows" (agent)
+-- [Generate Task] "Generate: Playwright project"
+-- [Approval Task] "Approval: Review generated tests"
+-- [Write Task] "Write: e2e/desktop/"
セッション復旧の確認
各呼び出しの開始時に、ほかの作業を行う前に、既存のタスクリストがあるか確認してください。
1. Read the current TaskList.
2. If no task list exists -> start from Phase 1.
3. If a task list exists:
a. Find the last task with status "completed".
b. Determine the corresponding phase.
c. Inform the user: "Resuming from Phase N -- [phase name]."
d. Skip to that phase's successor.
判断フローの全容については、このドキュメントの末尾にある「セッション復旧」セクションを参照してください。
変換パイプライン
このスキルは1つの入力ファイルを読み取り、完全なテストプロジェクトを生成します。
/workflows/desktop-workflows.md -> e2e/desktop/
+-- playwright.config.ts
+-- package.json
+-- tests/
| +-- auth.setup.ts
| +-- workflows.spec.ts
+-- .github/workflows/e2e.yml
+-- .gitignore
出力内の各ファイルは自己完結型です。実行時に元のワークフローMarkdownファイルに依存することはありません。ワークフローはPlaywrightテストコードに完全にコンパイルされます。
フェーズ1:ワークフローの解析
ワークフローのMarkdownファイルを読み取り、メタデータとともに各ワークフローを抽出して、後続のすべてのフェーズで使用する内部表現を作成します。
形式のリファレンス: 入力ワークフローファイルは、
docs/workflow-format.mdで定義されている形式に従います。見出しの形式、メタデータコメント、手順の形式、認識される動詞、アサーションの種類については、この仕様を参照してください。
手順1:ワークフローファイルの場所を特定する
Globを使用してワークフローファイルを検索します。
Glob patterns:
- workflows/desktop-workflows.md
- workflows/browser-workflows.md
ファイルが見つからない場合は、処理を停止してユーザーに知らせます。
No desktop workflow file found at /workflows/desktop-workflows.md.
Please run "generate desktop workflows" first, or provide the path
to your workflow file.
手順2:読み取りと解析
ワークフローファイル全体を読み取ります。各ワークフローについて、以下を抽出します。
- ワークフロー番号 --
## Workflow [N]:見出しから取得 - ワークフロー名 -- 番号の後に続く説明的な名前
- 認証要件 --
またはから取得 - 優先度 --
、、またはから取得 - 推定手順数 -- ``から取得
- 非推奨フラグ -- ``から取得(非推奨のワークフローはスキップ)
- 事前条件 --
**Preconditions:**の下にある箇条書き - 手順 -- 各番号付き手順と、その検証サブステップ
- 事後条件 --
**Postconditions:**の下にある箇条書き
手順3:内部表現の作成
ワークフローを構造化されたリストに整理します。
workflows = [
{
number: 1,
name: "User Registration",
auth: false,
priority: "core",
estimatedSteps: 7,
preconditions: ["User is on the landing page"],
steps: [
{ action: "Navigate to /signup", verify: "Signup form is visible" },
{ action: "Type 'John' in the first name field", verify: "Field shows 'John'" },
...
],
postconditions: ["User account exists", "User is redirected to dashboard"]
},
...
]
とマークされたワークフローはスキップします。スキップしたワークフローをユーザーに記録します。
Parsed 25 workflows from desktop-workflows.md.
Skipped 2 deprecated workflows: #7 (Legacy Export), #15 (Old Settings Page).
Converting 23 active workflows.
手順4:タスクの作成
TaskCreate:
title: "Convert: Desktop Workflows to Playwright"
status: "in_progress"
metadata:
source_file: "/workflows/desktop-workflows.md"
total_workflows: 25
active_workflows: 23
deprecated_skipped: 2
output_path: "e2e/desktop/"
TaskCreate:
title: "Parse: desktop-workflows.md"
status: "completed"
metadata:
workflows_parsed: 25
active: 23
deprecated: 2
core: 5
feature: 12
edge: 6
フェーズ2:既存プロジェクトの確認
生成を始める前に、e2e/desktop/ディレクトリがすでに存在するか確認します。
手順1:既存ファイルの確認
Globを使用して既存のプロジェクトファイルを確認します。
Glob patterns:
- e2e/desktop/playwright.config.ts
- e2e/desktop/package.json
- e2e/desktop/tests/*.spec.ts
- e2e/desktop/tests/*.setup.ts
手順2:方針の決定
既存プロジェクトが見つからない場合:
- 新規生成に進みます。
- 追加の判断は不要です。
既存プロジェクトが見つかった場合:
- 既存の
tests/workflows.spec.tsを読み取り、すでにカバーされている内容を把握します。 AskUserQuestionを使用して、ユーザーの意図を確認します。
I found an existing Playwright project at e2e/desktop/ with [N] existing test blocks.
How would you like to proceed?
1. **Overwrite** -- Replace all generated files with fresh output
2. **Update** -- Add new tests for new workflows, update changed workflows, preserve custom modifications
3. **Cancel** -- Stop and keep existing files unchanged
手順3:確認タスクの作成
TaskCreate:
title: "Check: Existing e2e/desktop/ project"
status: "completed"
metadata:
existing_project: true # or false
existing_tests: 18 # count of describe blocks
strategy: "overwrite" # or "update" or "fresh"
フェーズ3:セレクターの検出[エージェントに委任]
Exploreエージェントを起動してコードベースを分析し、ワークフロー内で参照されている要素に最適なPlaywrightセレクターを見つけます。
手順1:タスクの作成
TaskCreate:
title: "Selectors: Find for all workflows"
status: "in_progress"
metadata:
agent_type: "explore"
focus: "selectors"
手順2:Exploreエージェントの起動
次のパラメーターを指定して、Taskツールから起動します。
Task tool:
subagent_type: "Explore"
model: "sonnet"
prompt: |
You are a QA exploration agent focused on finding Playwright selectors.
Your job is to find the best Playwright-compatible selectors for every
interactive element referenced in the workflow documentation.
Use Read, Grep, and Glob to explore the codebase. Do NOT use any browser tools.
Here are the workflows I need selectors for:
[Paste the parsed workflow list with all step actions]
For each element, search for: data-testid, aria-label, role attributes,
<label> associations, placeholder text, and visible text content.
Prefer selectors in this order (Playwright recommended):
1. getByRole 2. getByLabel 3. getByPlaceholder
4. getByText 5. getByTestId 6. CSS selector (last resort)
Return findings as:
## Selector Map
| Workflow | Step | Element Description | Recommended Selector | Fallback Selector |
|----------|------|--------------------|--------------------|-------------------|
| 1 | 2 | "Save" button | getByRole('button', { name: 'Save' }) | getByTestId('save-btn') |
## Missing Selectors
- Elements not found in codebase (suggest data-testid additions)
## Selector Quality Report
- Counts by selector type and elements not found
ステップ 3:エージェントの結果を処理する
Explore エージェントが戻ったら、その Selector Map を内部のワークフロー表現に統合します。これで、各ステップにコード生成で使用する具体的な Playwright セレクターが設定されます。
TaskUpdate:
title: "Selectors: Find for all workflows"
status: "completed"
metadata:
selectors_found: 87
selectors_missing: 4
by_role: 42
by_label: 23
by_testid: 15
by_text: 7
css_fallback: 0
エージェントが特定できなかった要素については、テストコードにコメントを生成します。
// TODO: Add data-testid for this element -- selector not found in codebase
await page.locator('[data-testid="unknown-element"]').click();
フェーズ 4:Playwright プロジェクトを生成する
これは生成の中核となるフェーズです。解析済みのワークフロー、検出されたセレクター、設定テンプレートを使用して、プロジェクトのファイルをすべて生成します。
ステップ 1:生成タスクを作成する
TaskCreate:
title: "Generate: Playwright project"
status: "in_progress"
metadata:
files_to_generate: 6
ステップ 2:playwright.config.ts を生成する
Desktop Chrome をプライマリプロジェクトとして、認証セットアップを依存関係として設定し、Vercel のデプロイ保護をバイパスするヘッダーを含む Playwright 設定ファイルを生成します。
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
retries: process.env.CI ? 2 : 0,
reporter: process.env.CI ? 'html' : [['list'], ['html']],
use: {
baseURL: process.env.BASE_URL || 'http://localhost:3000',
trace: 'on-first-retry',
extraHTTPHeaders: {
...(process.env.VERCEL_AUTOMATION_BYPASS_SECRET && {
'x-vercel-protection-bypass': process.env.VERCEL_AUTOMATION_BYPASS_SECRET,
'x-vercel-set-bypass-cookie': 'samesitenone',
}),
},
},
projects: [
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
{
name: 'desktop-chromium',
use: {
...devices['Desktop Chrome'],
storageState: 'playwright/.auth/user.json',
},
dependencies: ['setup'],
},
],
});
主な設定上の決定事項:速度向上のための fullyParallel、CI でのみ不安定なテストを軽減する retries: 2、失敗のデバッグ用の trace: 'on-first-retry'、localhost とデプロイ済み URL の切り替えに対応するため環境変数から取得する baseURL です。Vercel のバイパスヘッダーは、VERCEL_AUTOMATION_BYPASS_SECRET が設定されている場合にのみ条件付きで適用されます。setup プロジェクトは、storageState に依存するテストの前に auth.setup.ts を実行します。
ステップ 3:tests/auth.setup.ts を生成する
認証セットアップファイルを生成します。ワークフローで認証が必要でない場合でも、このファイルは必ず生成されます。認証情報が指定されていない場合は、空のストレージ状態を問題なく保存するため、認証を必要としないテストも実行できます。
import { test as setup } from '@playwright/test';
import * as fs from 'fs';
import * as path from 'path';
const authFile = 'playwright/.auth/user.json';
setup('authenticate', async ({ page }) => {
// Check for saved profiles from /setup-profiles
const profilesDir = path.join(process.cwd(), '.playwright', 'profiles');
const profilesConfig = path.join(process.cwd(), '.playwright', 'profiles.json');
if (fs.existsSync(profilesConfig)) {
const config = JSON.parse(fs.readFileSync(profilesConfig, 'utf-8'));
const profileName = Object.keys(config.profiles)[0];
const profilePath = path.join(profilesDir, `${profileName}.json`);
if (fs.existsSync(profilePath)) {
const state = JSON.parse(fs.readFileSync(profilePath, 'utf-8'));
fs.mkdirSync(path.dirname(authFile), { recursive: true });
fs.writeFileSync(authFile, JSON.stringify(state));
return;
}
}
// Fall back to env-var credentials
if (!process.env.TEST_EMAIL || !process.env.TEST_PASSWORD) {
await page.context().storageState({ path: authFile });
return;
}
await page.goto('/login');
await page.getByLabel('Email').fill(process.env.TEST_EMAIL);
await page.getByLabel('Password').fill(process.env.TEST_PASSWORD);
await page.getByRole('button', { name: /sign in|log in/i }).click();
await page.waitForURL('**/dashboard');
await page.context().storageState({ path: authFile });
});
プロジェクトに /setup-profiles で作成されたプロファイルがある場合、認証セットアップは profiles.json を読み込み、最初に利用可能なプロファイルを特定して、その storageState を直接コピーします。ローカルのテスト実行では認証情報は必要ありません。CI では、代わりに環境変数の認証情報を使用します。
主な認証上の決定事項:認証情報が設定されていない場合は、空の認証状態を問題なく保存するため、認証を必要としないテストも引き続き成功します。正規表現のボタンマッチャー(/sign in|log in/i)は、一般的な表記の違いに対応します。特定のアプリケーション向けに生成する場合は、フェーズ 3 のセレクター検出結果に基づいて、ログインルート、フィールドラベル、ボタンテキスト、ログイン後の URL を調整します。
ステップ 4:package.json を生成する
{
"name": "desktop-e2e",
"private": true,
"scripts": {
"test": "playwright test",
"test:ui": "playwright test --ui",
"test:headed": "playwright test --headed"
},
"devDependencies": {
"@playwright/test": "^1.50.0"
}
}
ステップ 5:.github/workflows/e2e.yml を生成する
Vercel のプレビュー環境に対してテストを実行する GitHub Actions CI ワークフローを生成します。
name: Desktop E2E Tests
on: [deployment_status]
jobs:
test:
if: >
github.event.deployment_status.state == 'success' &&
contains(github.event.deployment_status.environment, 'Preview')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: cd e2e/desktop && npm ci
- run: cd e2e/desktop && npx playwright install chromium --with-deps
- run: cd e2e/desktop && npx playwright test
env:
BASE_URL: ${{ github.event.deployment_status.target_url }}
TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
VERCEL_AUTOMATION_BYPASS_SECRET: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }}
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: desktop-playwright-report
path: e2e/desktop/playwright-report/
主な CI 上の決定事項:実際の Vercel プレビュー URL に対してテストを実行するため、deployment_status でトリガーします。環境は Preview のみに絞り込み、target_url を BASE_URL として使用します。3 つの GitHub シークレット(TEST_EMAIL、TEST_PASSWORD、VERCEL_AUTOMATION_BYPASS_SECRET)が必要です。毎回の実行で Playwright HTML レポートをアーティファクトとしてアップロードし、速度向上のため Chromium のみをインストールします。
ステップ 6:.gitignore を生成する
node_modules/
playwright/.auth/
playwright-report/
test-results/
ステップ 7:tests/workflows.spec.ts を生成する
これは最大かつ最も重要なファイルです。解析済みの各ワークフローを test.describe() ブロックに、ワークフローの各ステップを 1 つ以上の Playwright アクションに対応付けます。
構造
import { test, expect } from '@playwright/test';
test.describe('Core Workflows', () => {
test.describe('Workflow 1: User Registration', () => {
test('completes user registration flow', async ({ page }) => {
// Step 1: Navigate to /signup
await page.goto('/signup');
// Verify: Signup form is visible
await expect(page.getByRole('heading', { name: 'Sign Up' })).toBeVisible();
// Step 2: Type "John" in the first name field
await page.getByLabel('First name').fill('John');
// Step 3: Type "[email protected]" in the email field
await page.getByLabel('Email').fill('[email protected]');
// Step 4: Click the "Create Account" button
await page.getByRole('button', { name: 'Create Account' }).click();
// Step 5: Verify success message appears
await expect(page.getByText('Account created successfully')).toBeVisible();
});
});
// ... more core workflow describe blocks
});
test.describe('Feature Workflows', () => {
// ... feature workflow describe blocks
});
test.describe('Edge Case Workflows', () => {
// ... edge case workflow describe blocks
});
グループ化のルール
- 最上位のグループ --
test.describe('Core Workflows', ...)、test.describe('Feature Workflows', ...)、test.describe('Edge Case Workflows', ...)は、ワークフローファイルの優先度レベルを反映します。 - ワークフローブロック -- 各ワークフローは、該当する優先度グループ内にネストされた
test.describe('Workflow N: Name', ...)になります。 - ワークフローごとにテストを 1 つ作成 -- 各ワークフローは、すべてのステップを順番に含む単一の
test()呼び出しになります。これにより各ワークフローが不可分となり、全体として成功するか失敗するかのどちらかになります。 - ステップコメント -- ワークフローの各ステップの前にコメント(
// Step N: ...)を、その検証の前にコメント(// Verify: ...)を記述します。
ステップの変換ルール
ワークフローのステップを Playwright コードに変換する際は、以下のルールを適用します。各要素に最適なセレクターを選ぶには、フェーズ 3 の Selector Map を使用します。
// Navigation
await page.goto('/dashboard');
// Click actions
await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('link', { name: 'Settings' }).click();
await page.getByText('Learn more').click();
// Type / fill actions
await page.getByLabel('Email').fill('[email protected]');
await page.getByPlaceholder('Search...').fill('search term');
// Select, checkbox, toggle
await page.getByLabel('Role').selectOption('Admin');
await page.getByLabel('Remember me').check();
await page.getByLabel('Send notifications').uncheck();
// Wait and visibility
await expect(page.getByText('Loading')).toBeHidden();
await page.waitForURL('**/dashboard');
// Verification assertions
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
await expect(page.getByText('Changes saved')).toBeVisible();
await expect(page).toHaveURL(/.*\/settings/);
await expect(page).toHaveTitle('Settings');
// File upload, keyboard, hover, scroll
await page.getByLabel('Upload').setInputFiles('report.pdf');
await page.keyboard.press('Escape');
await page.getByRole('menuitem', { name: 'Settings' }).hover();
await page.getByText('Comments').scrollIntoViewIfNeeded();
[MANUAL] ステップの処理
[MANUAL] とマークされたワークフローステップは自動化できません。スキップするテストステップ、または注釈付きのテストステップを生成します。
// Step 4: [MANUAL] Verify the email arrives in the user's inbox
// This step requires manual verification -- cannot be automated with Playwright.
// Consider using a test email service (e.g., Mailosaur) for automation.
ワークフローの一部のステップのみが手動の場合、ワークフロー全体に対して test.skip() を生成しないでください。代わりにコメントを追加し、その後の自動化可能なステップを続けてください。
前提条件の処理
ワークフローに認証以外の前提条件がある場合は、test.beforeEach またはインラインのセットアップコードとして生成します。
test.describe('Workflow 5: Edit Existing Post', () => {
test('edits an existing post successfully', async ({ page }) => {
// Precondition: At least one post exists
// Navigate to the posts list to verify
await page.goto('/posts');
await expect(page.getByRole('article')).toHaveCount(1, { timeout: 5000 });
// Step 1: Click the first post title
await page.getByRole('article').first().click();
// ...
});
});
ステップ 8:生成タスクを更新する
TaskUpdate:
title: "Generate: Playwright project"
status: "completed"
metadata:
files_generated: 6
test_describes: 23
total_steps_translated: 142
manual_steps_skipped: 3
selectors_from_agent: 87
アクション対応表
この表は、ワークフローの言語から Playwright コードへの完全な対応を示しています。ステップを変換する際のクイックリファレンスとして使用してください。
| ワークフローの言語 | Playwright コード |
|---|---|
| /dashboard に移動する | await page.goto('/dashboard') |
| 「Save」ボタンをクリックする | await page.getByRole('button', { name: 'Save' }).click() |
| 「Settings」リンクをクリックする | await page.getByRole('link', { name: 'Settings' }).click() |
| メールフィールドに「hello」と入力する | await page.getByLabel('Email').fill('hello') |
| 検索ボックスに「query」と入力する | await page.getByPlaceholder('Search...').fill('query') |
| 見出し「Dashboard」が表示されていることを確認する | await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible() |
| テキスト「Success」が表示されることを確認する | await expect(page.getByText('Success')).toBeVisible() |
| URL に /settings が含まれていることを確認する | await expect(page).toHaveURL(/.*\/settings/) |
| ロールのドロップダウンから「Admin」を選択する | await page.getByLabel('Role').selectOption('Admin') |
| 「Remember me」チェックボックスをオンにする | await page.getByLabel('Remember me').check() |
| 「Notifications」チェックボックスをオフにする | await page.getByLabel('Notifications').uncheck() |
| 読み込み表示が消えるまで待機する | await expect(page.getByText('Loading')).toBeHidden() |
| URL に /dashboard が含まれるまで待機する | await page.waitForURL('**/dashboard') |
| 「file.pdf」をアップロードする | await page.getByLabel('Upload').setInputFiles('file.pdf') |
| Escape キーを押す | await page.keyboard.press('Escape') |
| Enter キーを押して送信する | await page.keyboard.press('Enter') |
| 「Settings」メニュー項目にカーソルを合わせる | await page.getByRole('menuitem', { name: 'Settings' }).hover() |
| コメントセクションまでスクロールする | await page.getByText('Comments').scrollIntoViewIfNeeded() |
| 「Task A」を「Done」列にドラッグする | await page.getByText('Task A').dragTo(page.getByText('Done')) |
| 要素の件数が N であることを確認する | await expect(page.getByRole('listitem')).toHaveCount(N) |
| 入力欄の値が「text」であることを確認する | await expect(page.getByLabel('Name')).toHaveValue('text') |
| 検索フィールドをクリアする | await page.getByLabel('Search').clear() |
変換例
以下は、desktop-workflows.md のワークフローを Playwright テストコードに変換する完全な実例です。
入力ワークフロー
## Workflow 3: Create New Post
> Tests the complete flow of creating a new blog post from the dashboard.
**Preconditions:**
- User is logged in as editor
**Steps:**
1. Navigate to /dashboard
- Verify the dashboard heading is visible
2. Click the "New Post" button
- Verify the post editor page loads
3. Type "My First Post" in the title field
- Verify the title field shows "My First Post"
4. Type "This is the post body content." in the content editor
- Verify content appears in the editor
5. Select "Technology" from the category dropdown
- Verify "Technology" is selected
6. Click the "Publish" button
- Verify success toast appears with message "Post published"
7. Verify the URL changes to /posts/[slug]
8. Navigate to /posts
- Verify "My First Post" appears in the post list
**Postconditions:**
- New post exists with title "My First Post"
- Post is visible in the public post list
出力テストコード
test.describe('Workflow 3: Create New Post', () => {
test('creates a new blog post from the dashboard', async ({ page }) => {
// Step 1: Navigate to /dashboard
await page.goto('/dashboard');
// Verify: The dashboard heading is visible
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
// Step 2: Click the "New Post" button
await page.getByRole('button', { name: 'New Post' }).click();
// Verify: The post editor page loads
await expect(page.getByRole('heading', { name: /editor|new post/i })).toBeVisible();
// Step 3: Type "My First Post" in the title field
await page.getByLabel('Title').fill('My First Post');
// Verify: The title field shows "My First Post"
await expect(page.getByLabel('Title')).toHaveValue('My First Post');
// Step 4: Type "This is the post body content." in the content editor
await page.getByLabel('Content').fill('This is the post body content.');
// Verify: Content appears in the editor
await expect(page.getByLabel('Content')).toHaveValue('This is the post body content.');
// Step 5: Select "Technology" from the category dropdown
await page.getByLabel('Category').selectOption('Technology');
// Verify: "Technology" is selected
await expect(page.getByLabel('Category')).toHaveValue('Technology');
// Step 6: Click the "Publish" button
await page.getByRole('button', { name: 'Publish' }).click();
// Verify: Success toast appears
await expect(page.getByText('Post published')).toBeVisible();
// Step 7: Verify the URL changes to /posts/[slug]
await expect(page).toHaveURL(/\/posts\/.+/);
// Step 8: Navigate to /posts
await page.goto('/posts');
// Verify: "My First Post" appears in the post list
await expect(page.getByText('My First Post')).toBeVisible();
});
});
変換に関する注意点
主なパターン:ステップのコメントは相互参照できるようワークフローのテキストを反映し、「Verify」の各サブステップは expect() アサーションになり、セレクターは優先順位(role > label > text > testid)に従い、Phase 3 のオーバーライドを適用します。テスト名はワークフローの説明から導出し、動的な URL セグメントには正規表現パターンを使用します。
フェーズ 5:ユーザーによるレビュー(必須)
このフェーズは必須です。ユーザーの承認なしにファイルを書き込んではいけません。
生成したテストをレビュー用に提示する
AskUserQuestion を使用して、生成したプロジェクトを提示します。
I have generated a Playwright test project from [N] desktop workflows.
Project structure:
e2e/desktop/
+-- playwright.config.ts (Desktop Chrome, auth setup, Vercel bypass)
+-- package.json (Playwright dependency + test scripts)
+-- tests/
| +-- auth.setup.ts (Authentication scaffolding)
| +-- workflows.spec.ts ([N] test blocks, [M] total steps)
+-- .github/workflows/e2e.yml (CI on Vercel preview deployments)
+-- .gitignore
Test summary:
- Core tests: [X] workflows
- Feature tests: [Y] workflows
- Edge case tests: [Z] workflows
- Manual steps (commented): [K]
- Selectors from codebase analysis: [S]
Here are the generated test files:
[Paste the complete tests/workflows.spec.ts]
[Paste auth.setup.ts if customized from default]
Please review and let me know:
1. Are any test translations incorrect?
2. Should any selectors be adjusted?
3. Are there any missing edge cases?
4. Any changes to the auth setup flow?
Reply "approved" to write all files, or provide feedback for revision.
承認タスクを作成する
TaskCreate:
title: "Approval: Review generated tests"
status: "in_progress"
metadata:
iteration: 1
test_blocks_presented: 23
total_steps: 142
フィードバックの処理
ユーザーが承認する代わりにフィードバックを提供した場合:
- 生成したファイルに、要求された変更を適用します。
- 承認タスクを更新します。
TaskUpdate:
title: "Approval: Review generated tests"
status: "completed"
metadata:
iteration: 1
result: "changes_requested"
feedback_summary: "Fix login selector, add timeout to dashboard load"
- 次のレビュー用に新しい承認タスクを作成します。
TaskCreate:
title: "Approval: Review generated tests #2"
status: "in_progress"
metadata:
iteration: 2
changes_made: ["fixed login selector", "added timeout to dashboard load"]
- 修正したテストを再度ユーザーに提示します。
ユーザーが「approved」または同等の肯定的な返答をするまで繰り返します。
承認された場合
TaskUpdate:
title: "Approval: Review generated tests"
status: "completed"
metadata:
iteration: 1
result: "approved"
final_test_count: 23
フェーズ 6:ファイルを書き込む
生成したすべてのファイルを e2e/desktop/ に書き込みます。
ステップ 1:ディレクトリ構造を作成する
1. Ensure e2e/desktop/ exists (create if not).
2. Ensure e2e/desktop/tests/ exists (create if not).
3. Ensure .github/workflows/ exists (create if not).
ステップ 2:すべてのファイルを書き込む
各ファイルを次の順番で書き込みます。
e2e/desktop/playwright.config.tse2e/desktop/package.jsone2e/desktop/tsconfig.jsone2e/desktop/tests/auth.setup.tse2e/desktop/tests/workflows.spec.tse2e/desktop/.gitignore.github/workflows/e2e.yml(注:これはe2e/desktop/内ではなく、リポジトリのルートにあります)
tsconfig.json の内容:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["tests/**/*.ts"]
}
ステップ 3:ファイルを確認する
書き込み後、各ファイルを読み返し、正しく書き込まれていることを確認します。
Use Read tool to verify:
- e2e/desktop/playwright.config.ts
- e2e/desktop/package.json
- e2e/desktop/tsconfig.json
- e2e/desktop/tests/auth.setup.ts
- e2e/desktop/tests/workflows.spec.ts
- e2e/desktop/.gitignore
- .github/workflows/e2e.yml
ステップ 4:生成したコードの型チェック
生成したプロジェクトに対して TypeScript の型チェックを実行し、プロジェクトの完成として提示する前にコンパイルエラーを検出します。
前提条件: tsc が利用可能である必要があります。npx tsc --version が失敗した場合は、e2e/desktop ディレクトリで npm install typescript --save-dev を実行してみてください。それでも TypeScript が見つからない場合は処理を停止し、ユーザーに「型チェックには TypeScript コンパイラー(tsc)が必要ですが、見つかりませんでした。npm install -D typescript でインストールするか、グローバルに利用できることを確認してください。」と伝えます。型チェックは必須です。省略してはいけません。
手順:
1. Install dependencies (capture errors for diagnosis):
cd e2e/desktop && npm install --ignore-scripts 2>&1 | tee /tmp/npm-install.log
2. Run type-check:
cd e2e/desktop && npx tsc --noEmit
3. If type errors are found:
a. Read the tsc error output to identify the failing file and line.
b. Fix the type error in the generated code.
c. IMPORTANT: Write modified files back to disk BEFORE the next tsc run.
Do not batch fixes — write each fix immediately so the next tsc run
sees the corrected code on disk.
d. Re-run: cd e2e/desktop && npx tsc --noEmit
e. Repeat up to a 3-attempt cap (counted per full tsc run, not per error).
After 3 full tsc runs with errors, STOP and use AskUserQuestion to
present the remaining errors to the user and ask for guidance.
セマンティックガード: 修正ループでは、アサーション、セレクター、テストの意図を変更してはいけません。修正は次の範囲に限定します。
- 型注釈(型の明示的な追加、型の不一致の修正)
- インポート文(不足しているインポート、誤ったインポートパス)
- API の使用方法の修正(Playwright API メソッドのシグネチャの誤り)
修正によってテストの内容が変わる場合(アサーションの変更、セレクターの変更、テストロジックの変更、テスト手順の削除)は、適用してはいけません。その代わりに、AskUserQuestion を使ってユーザーに確認します。
Type error in [file]:[line] requires changing test intent to fix:
Error: [tsc error message]
Current code: [the line with the error]
Fixing this would require changing [what would change — e.g., the assertion,
the selector, the test logic]. This is beyond the scope of type-error fixes.
How would you like to proceed?
1. Fix it manually
2. Suppress with // @ts-expect-error and move on
3. Remove the affected test block
ステップ 5:タスクを更新する
TaskCreate:
title: "Write: e2e/desktop/"
status: "completed"
metadata:
files_written: 6
output_directory: "e2e/desktop/"
ci_workflow: ".github/workflows/e2e.yml"
TaskUpdate:
title: "Convert: Desktop Workflows to Playwright"
status: "completed"
metadata:
source_file: "/workflows/desktop-workflows.md"
total_workflows_converted: 23
files_written: 6
output_directory: "e2e/desktop/"
ci_workflow: ".github/workflows/e2e.yml"
review_iterations: 1
最終サマリー
完了内容の概要をユーザーに提示します。
Desktop workflow-to-Playwright conversion complete.
Output directory: e2e/desktop/
CI workflow: .github/workflows/e2e.yml
Files written:
- playwright.config.ts (config with auth + Vercel bypass)
- package.json (Playwright dependency)
- tests/auth.setup.ts (authentication scaffolding)
- tests/workflows.spec.ts (23 test blocks, 142 steps)
- .gitignore (excludes auth state + reports)
- e2e.yml (GitHub Actions CI workflow)
Summary:
- Workflows converted: 23 (5 core, 12 feature, 6 edge)
- Deprecated skipped: 2
- Manual steps commented: 3
- Selectors from codebase: 87
- Review iterations: 1
Next steps:
1. cd e2e/desktop && npm install && npx playwright install chromium
2. npx playwright test --headed (run locally in headed mode)
3. npx playwright test --ui (use Playwright UI mode for debugging)
4. Configure GitHub secrets: TEST_EMAIL, TEST_PASSWORD, VERCEL_AUTOMATION_BYPASS_SECRET
5. Push to trigger CI on next Vercel preview deployment
セッションの復旧
スキルが呼び出され、既存のタスクリストが見つかった場合は、この判断ツリーを使って再開地点を決定します。
判断ツリー
Check TaskList for "Convert: Desktop Workflows to Playwright"
CASE 1: No task list exists
-> Start from Phase 1
CASE 2: Parse task is "completed", no Check task
-> Workflow file has been parsed
-> Resume from Phase 2 (check existing project)
CASE 3: Check task is "completed", no Selector task
-> Existing project has been checked
-> Resume from Phase 3 (selector discovery)
CASE 4: Selector task is "in_progress"
-> Agent may have timed out
-> Re-spawn the Explore agent
-> Resume from Phase 3 (partial)
CASE 5: Selector task is "completed", no Generate task
-> Selectors have been discovered
-> Resume from Phase 4 (generate project)
CASE 6: Generate task is "completed", no Approval task
-> Files were generated but not reviewed
-> Resume from Phase 5 (review with user)
CASE 7: Approval task exists with result "changes_requested"
-> User gave feedback but revisions were not completed
-> Read the feedback from task metadata
-> Apply changes and re-present for review
-> Resume from Phase 5 (next iteration)
CASE 8: Approval task is "completed" with result "approved", no Write task
-> Tests were approved but files were not written
-> Resume from Phase 6 (write files)
CASE 9: Write task is "completed"
-> Everything is done
-> Show the final summary and ask if the user wants to make changes
再開時は必ずユーザーに伝える
I found an existing session for desktop workflow-to-Playwright conversion.
Current state: [describe where things left off]
Last completed phase: [phase name]
I will resume from [next phase]. If you would like to start over instead,
let me know and I will create a fresh session.
更新の処理
ユーザーが「更新」モード(変更されたワークフローに合わせて既存のテストを修正するモード)を選んだ場合は、次のルールに従います。
既存テストを更新する際のルール
-
カスタム変更を保持する -- ユーザーが生成されたテストを手動で編集している場合(カスタムヘルパーの追加、セレクターの変更、追加のアサーションなど)は、その編集を保持します。
// CUSTOM:のようなコメントや、生成されたパターンと一致しないコードを探してください。 -
ワークフローとテストブロックを対応付ける --
test.describe('Workflow N: ...')という命名規則を使って、既存のテストブロックを元のワークフローに対応付けます。このため、一貫した命名が重要です。 -
変更されたワークフローを更新する -- 前回の生成以降にワークフローの手順が変更されている場合は、そのワークフローの
test.describeブロックのみを再生成します。ファイル内でのブロックの位置は維持します。 -
新しいワークフローを追加する -- 新しいワークフローは、適切な優先度グループ(
Core Workflows、Feature Workflows、Edge Case Workflows)に追加します。各グループの末尾に追加します。 -
削除されたワークフローに印を付ける -- 前回の生成以降にワークフローが廃止されている場合は、テストブロックを削除せず、コメントアウトします。
// DEPRECATED: Workflow 7 -- Legacy Export Feature
// Reason: Export feature removed in v2.3
// Date: 2025-01-15
// test.describe('Workflow 7: Legacy Export Feature', () => { ... });
-
設定ファイルを再生成する --
playwright.config.ts、package.json、.gitignore、CI ワークフローは、常にテンプレートから再生成します(カスタム変更を含めてはいけません)。 -
auth.setup.tsのカスタマイズを保持する -- ユーザーが認証設定(異なるログインフロー、複数ステップの認証など)をカスタマイズしている場合は、そのバージョンを保持します。ユーザーが明示的に要求した場合に限り、再生成します。
更新サマリー
更新処理の後、変更内容の概要を提示します。
Desktop Playwright test update complete.
Changes to tests/workflows.spec.ts:
- Test blocks preserved (unchanged): 18
- Test blocks updated (steps changed): 3
- Test blocks deprecated (commented out): 1
- Test blocks added (new workflows): 2
Changed tests:
- Workflow 4: Updated steps 3-5 (new form field added)
- Workflow 12: Updated step 1 (route changed to /preferences)
- Workflow 19: Updated steps 5-7 (confirmation dialog added)
Deprecated tests:
- Workflow 7: Legacy Export Feature
New tests:
- Workflow 26: Dashboard Widget Customization
- Workflow 27: Real-Time Notification Center
Files regenerated: playwright.config.ts, package.json, .gitignore, e2e.yml
Files preserved: auth.setup.ts (custom modifications detected)
セレクター戦略のリファレンス
ワークフローのステップを Playwright コードに変換するときは、常に最も堅牢なセレクターを優先してください。この表は、Playwright の公式推奨に沿った優先順位を示しています。
| 優先順位 | 戦略 | 使用する場面 | 例 |
|---|---|---|---|
| 1 | getByRole | ボタン、リンク、見出し、チェックボックス、ラジオボタン、および明示的な ARIA ロールを持つすべての要素 | page.getByRole('button', { name: 'Submit' }) |
| 2 | getByLabel | 関連付けられた <label> 要素または aria-label 属性を持つフォーム入力 | page.getByLabel('Email address') |
| 3 | getByPlaceholder | ラベルはないものの、プレースホルダーテキストがある入力 | page.getByPlaceholder('Search...') |
| 4 | getByText | 表示テキストで特定できる、操作できない要素 | page.getByText('Welcome back') |
| 5 | getByTestId | data-testid 属性を持つ要素。他のセレクターでは曖昧になる場合に便利 | page.getByTestId('sidebar-nav') |
| 6 | CSS セレクター | セマンティックセレクターが使えない場合の最終手段 | page.locator('.custom-widget > .action-btn') |
セレクターのアンチパターン
生成するテストでは、ID セレクター(#submit-btn)、クラスセレクター(.btn-primary)、構造セレクター(div > span:nth-child(3))、属性セレクター([onclick="save()"])を避けてください。これらはすべて壊れやすく、リファクタリング時に動作しなくなります。上記の優先順位表にあるセマンティックロケーターを常に優先してください。
制約事項
- 使用可能なツール -- このスキルでは、Read、Write、Glob、Grep、および Task/Explore ツールのみを使用します。Chrome MCP、iOS Simulator MCP、Playwright CLI、その他のブラウザー自動化ツールは使用しないでください。ブラウザー操作はすべてコードとして生成し、変換中に実行することはありません。
- 出力先 -- すべてのテストファイルは
e2e/desktop/に配置します。CI ワークフローは、リポジトリのルートにある.github/workflows/e2e.ymlに配置します。 - 認証は常に生成 -- 認証を必要とするワークフローがゼロの場合でも、
auth.setup.tsは必ず含めます。認証情報がない場合も適切に処理します。 - Vercel ヘッダーは常に含める -- 環境変数が設定されている場合、
playwright.config.tsでx-vercel-protection-bypassヘッダーとx-vercel-set-bypass-cookieヘッダーを条件付きで適用します。 - ワークフローへの実行時依存なし -- 生成されるテストプロジェクトは完全に自己完結しています。実行時にワークフローの Markdown ファイルを読み込んだり、そこからインポートしたりすることはありません。
- Playwright のベストプラクティス --
getByRole、getByLabel、getByText、getByPlaceholder、getByTestIdの順に使用してください。絶対に必要な場合を除き、CSS セレクターと XPath セレクターは避けてください。