prowler-test-ui について
prowler-test-uiは、ProwlerのUIエンドツーエンドテスト向けスキルです。プロジェクト固有のPlaywright規約を示し、テストとMarkdown文書の同期や、作成前のMCPツールによる実画面の確認を重視します。
主な機能
- 01UIテストのディレクトリー構成
- 02テストと文書の同期要件
- 03作成前のページ探索
- 04待機とナビゲーション検証の規約
- 05テストタグとコマンドの指定
活用シーン
- 01Prowler画面のエンドツーエンドテスト追加
- 02テスト変更に伴うケース文書の更新
- 03実際の画面構造に基づくテスト作成
MCP 対応
テスト作成前にPlaywright MCPツールで対象ページへ移動し、スナップショットの確認と要素の操作を行って、実際の構造やセレクターを確かめる手順を示します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ prowler-cloud/ prowler --skill prowler-test-uiインストール後、Claude Code で/prowler-test-uiを入力して読み込まれたか確認します。
同梱ファイルreferences/e2e-docs.md
詳細
一般的なパターン:Page Object Model、セレクター、ヘルパーなどの基本的な Playwright パターンについては、
playwrightスキルを参照してください。 このスキルでは Prowler 固有の規約のみを扱います。
Prowler UI テストの構成
ui/tests/
├── base-page.ts # Prowler-specific base page
├── helpers.ts # Prowler test utilities
└── {page-name}/
├── {page-name}-page.ts # Page Object Model
├── {page-name}.spec.ts # ALL tests (single file per feature)
└── {page-name}.md # Test documentation (MANDATORY - sync with spec.ts)
必須チェックリスト(テストの作成または変更)
⚠️ E2E タスクを完了する前に、必ず確認してください:
新しいテストを作成する場合
-
{page-name}-page.ts- Page Object を作成または更新する -
{page-name}.spec.ts- 正しいタグ(@TEST-ID)を付けてテストを追加する -
{page-name}.md- すべてのテストケースを含むドキュメントを作成する -
.mdのテスト ID が.spec.tsのタグと一致している
既存のテストを変更する場合
- 次の場合、
{page-name}.mdを必ず更新する:- テストケースを追加または削除した
- テストフロー(手順)を変更した
- 前提条件または期待される結果を変更した
- タグまたは優先度を変更した
-
.mdと.spec.tsのテスト ID が同期している
簡易検証
# Verify .md exists for each test folder
ls ui/tests/{feature}/{feature}.md
# Verify test IDs match
grep -o "@[A-Z]*-E2E-[0-9]*" ui/tests/{feature}/{feature}.spec.ts | sort -u
grep -o "\`[A-Z]*-E2E-[0-9]*\`" ui/tests/{feature}/{feature}.md | sort -u
重要
❌ 対応する
.mdファイルを更新しない限り、E2E の変更は完了したとは見なされません。
MCP ワークフロー - 重要
⚠️ 必須:Playwright MCP ツールが利用可能な場合は、テストを作成する前に必ず使用してください。
- 対象ページに移動する
- 実際の DOM 構造を確認するためにスナップショットを取得する
- 実際のフローを確認するためにフォームや要素を操作する
- スナップショットから実際のセレクターを記録する
- その後でテストコードを書く
理由:推測に基づくテストを防ぎます。実際に調査することで、安定したテストを作成できます。
待機戦略(重要)
⚠️ networkidle は絶対に使用しないでください。テストが不安定になります!
| 戦略 | 用途 |
|---|---|
❌ networkidle | 絶対に使用しない - ポーリングや WebSocket で不安定になります |
⚠️ load | どうしても必要な場合のみ |
✅ expect(element).toBeVisible() | 推奨 - 特定の UI 状態を待機します |
✅ page.waitForURL() | ページ遷移を待機します |
✅ pageObject.verifyPageLoaded() | 最適 - 検証をカプセル化します |
良い例:
await homePage.verifyPageLoaded();
await expect(page).toHaveURL("/dashboard");
await expect(page.getByRole("heading", { name: "Overview" })).toBeVisible();
悪い例:
await page.waitForLoadState("networkidle"); // ❌ FLAKY
await page.waitForTimeout(2000); // ❌ ARBITRARY WAIT
Prowler 基本ページ
import { Page, Locator, expect } from "@playwright/test";
export class BasePage {
constructor(protected page: Page) {}
async goto(path: string): Promise<void> {
await this.page.goto(path);
// Child classes should override verifyPageLoaded() to wait for specific elements
}
// Override in child classes to wait for page-specific elements
async verifyPageLoaded(): Promise<void> {
await expect(this.page.locator("main")).toBeVisible();
}
// Prowler-specific: notification handling
async waitForNotification(): Promise<Locator> {
const notification = this.page.locator('[role="status"]');
await notification.waitFor({ state: "visible" });
return notification;
}
async verifyNotificationMessage(message: string): Promise<void> {
const notification = await this.waitForNotification();
await expect(notification).toContainText(message);
}
}
ページ遷移の検証パターン
⚠️ URL のアサーションは Page Object に記述し、テストには記述しないでください!
リダイレクトやページ遷移を検証する場合は、遷移先の Page Object に専用のメソッドを作成します。
// ✅ GOOD - In SignInPage
async verifyOnSignInPage(): Promise<void> {
await expect(this.page).toHaveURL(/\/sign-in/);
await expect(this.pageTitle).toBeVisible();
}
// ✅ GOOD - In test
await homePage.goto(); // Try to access protected route
await signInPage.verifyOnSignInPage(); // Verify redirect
// ❌ BAD - Direct assertions in test
await homePage.goto();
await expect(page).toHaveURL(/\/sign-in/); // Should be in Page Object
await expect(page.getByText("Sign in")).toBeVisible();
命名規則: リダイレクト検証メソッドには verifyOn{PageName}Page() を使用します。
Prowler 固有のページ
プロバイダーページ
import { BasePage } from "../base-page";
export class ProvidersPage extends BasePage {
readonly addButton = this.page.getByRole("button", { name: "Add Provider" });
readonly providerTable = this.page.getByRole("table");
async goto(): Promise<void> {
await super.goto("/providers");
}
async addProvider(type: string, alias: string): Promise<void> {
await this.addButton.click();
await this.page.getByLabel("Provider Type").selectOption(type);
await this.page.getByLabel("Alias").fill(alias);
await this.page.getByRole("button", { name: "Create" }).click();
}
}
スキャンページ
export class ScansPage extends BasePage {
readonly newScanButton = this.page.getByRole("button", { name: "New Scan" });
readonly scanTable = this.page.getByRole("table");
async goto(): Promise<void> {
await super.goto("/scans");
}
async startScan(providerAlias: string): Promise<void> {
await this.newScanButton.click();
await this.page.getByRole("combobox", { name: "Provider" }).click();
await this.page.getByRole("option", { name: providerAlias }).click();
await this.page.getByRole("button", { name: "Start Scan" }).click();
}
}
Prowler のテストタグ
test("Provider CRUD operations",
{ tag: ["@critical", "@e2e", "@providers", "@PROV-E2E-001"] },
async ({ page }) => {
// ...
}
);
| カテゴリー | タグ |
|---|---|
| 優先度 | @critical、@high、@medium、@low |
| 種類 | @e2e、@smoke、@regression |
| 機能 | @providers、@scans、@findings、@compliance、@signin、@signup |
| テスト ID | @PROV-E2E-001、@SCAN-E2E-002 |
Prowler テストドキュメントのテンプレート
60 行以内に収めてください。フロー、前提条件、期待される結果のみに重点を置いてください。
### E2E Tests: {Feature Name}
**Suite ID:** `{SUITE-ID}`
**Feature:** {Feature description}
---
## Test Case: `{TEST-ID}` - {Test case title}
**Priority:** `{critical|high|medium|low}`
**Tags:** @e2e, @{feature-name}
**Preconditions:**
- {Prerequisites}
### Flow Steps:
1. {Step}
2. {Step}
### Expected Result:
- {Outcome}
### Key Verification Points:
- {Assertion}
コマンド
cd ui && pnpm run test:e2e # All tests
cd ui && pnpm run test:e2e tests/providers/ # Specific folder
cd ui && pnpm run test:e2e --grep "provider" # By pattern
cd ui && pnpm run test:e2e:ui # With UI
cd ui && pnpm run test:e2e:debug # Debug mode
cd ui && pnpm run test:e2e:headed # See browser
cd ui && pnpm run test:e2e:report # Generate report
リソース
- ドキュメント:ローカルの開発者ガイドへのリンクについては、references/ を参照してください。