
Prowler Test UI
FreeStreamline E2E testing for Prowler UI with Playwright.
Free · Opens the source repo
What Prowler Test UI does
Prowler Test UI is a specialized skill designed for developers working with the Prowler UI framework, specifically when writing end-to-end (E2E) tests using Playwright. This skill provides a structured approach to creating and managing tests that adhere to Prowler-specific conventions, ensuring consistency and reliability in your testing process. It emphasizes the importance of maintaining accurate documentation and synchronization between test specifications and their corresponding documentation files.
The skill includes a set of guidelines and mandatory checklists that must be followed when creating or modifying tests. This ensures that every test case is documented correctly, with clear mappings between test IDs and their respective specifications. The structured test folder layout encourages best practices in test organization, making it easier to navigate and manage your test suite.
Additionally, Prowler Test UI emphasizes the use of Playwright's MCP tools for creating tests based on actual DOM structures rather than assumptions. This approach helps in writing more stable tests by verifying the real flow of the application before coding the tests. The skill also provides critical insights on wait strategies to avoid flaky tests, promoting the use of specific UI state assertions over generic wait conditions.
This skill is ideal for developers and QA engineers who are involved in testing Prowler UI applications. It helps streamline the testing process while ensuring adherence to best practices, ultimately leading to more reliable and maintainable test suites.
When to use it
Use this skill when developing E2E tests for Prowler UI applications to ensure compliance with Prowler-specific testing patterns.
When not to use it
This skill is not suitable for general Playwright testing outside of the Prowler UI context or for projects that do not require Prowler-specific conventions.
What you can build with it
Creating New E2E Tests
When starting a new feature in Prowler UI, use this skill to ensure all necessary documentation and test structures are in place.
Modifying Existing Tests
If you need to update tests in Prowler UI, follow the mandatory checklist to maintain synchronization between test specs and documentation.
Validating Test Stability
Before finalizing E2E tests, utilize the MCP tools to explore the actual DOM and ensure tests are based on real application behavior.
How to install Prowler Test UI
View source1. Install with the skills CLI
npx skills add prowler-cloud/prowler/prowler-test-ui --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by prowler-cloudGeneric Patterns: For base Playwright patterns (Page Object Model, selectors, helpers), see the
playwrightskill. This skill covers Prowler-specific conventions only.
Prowler UI Test Structure
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)
MANDATORY Checklist (Create or Modify Tests)
⚠️ ALWAYS verify BEFORE completing any E2E task:
When CREATING new tests
-
{page-name}-page.ts- Page Object created/updated -
{page-name}.spec.ts- Tests added with correct tags (@TEST-ID) -
{page-name}.md- Documentation created with ALL test cases - Test IDs in
.mdmatch tags in.spec.ts
When MODIFYING existing tests
-
{page-name}.mdMUST be updated if:- Test cases were added/removed
- Test flow changed (steps)
- Preconditions or expected results changed
- Tags or priorities changed
- Test IDs synchronized between
.mdand.spec.ts
Quick validation
# 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
[!IMPORTANT] ❌ An E2E change is NOT considered complete without updating the corresponding
.mdfile.
MCP Workflow - CRITICAL
⚠️ MANDATORY: If Playwright MCP tools are available, ALWAYS use them BEFORE creating tests.
- Navigate to target page
- Take snapshot to see actual DOM structure
- Interact with forms/elements to verify real flow
- Document actual selectors from snapshots
- Only then write test code
Why: Prevents tests based on assumptions. Real exploration = stable tests.
Wait Strategies (CRITICAL)
⚠️ NEVER use networkidle - it causes flaky tests!
| Strategy | Use Case |
|---|---|
❌ networkidle | NEVER - flaky with polling/WebSockets |
⚠️ load | Only when absolutely necessary |
✅ expect(element).toBeVisible() | PREFERRED - wait for specific UI state |
✅ page.waitForURL() | Wait for navigation |
✅ pageObject.verifyPageLoaded() | BEST - encapsulated verification |
GOOD:
await homePage.verifyPageLoaded();
await expect(page).toHaveURL("/dashboard");
await expect(page.getByRole("heading", { name: "Overview" })).toBeVisible();
BAD:
await page.waitForLoadState("networkidle"); // ❌ FLAKY
await page.waitForTimeout(2000); // ❌ ARBITRARY WAIT
Prowler Base Page
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);
}
}
Page Navigation Verification Pattern
⚠️ URL assertions belong in Page Objects, NOT in tests!
When verifying redirects or page navigation, create dedicated methods in the target 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();
Naming convention: verifyOn{PageName}Page() for redirect verification methods.
Prowler-Specific Pages
Providers Page
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();
}
}
Scans Page
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();
}
}
Test Tags for Prowler
test("Provider CRUD operations",
{ tag: ["@critical", "@e2e", "@providers", "@PROV-E2E-001"] },
async ({ page }) => {
// ...
}
);
| Category | Tags |
|---|---|
| Priority | @critical, @high, @medium, @low |
| Type | @e2e, @smoke, @regression |
| Feature | @providers, @scans, @findings, @compliance, @signin, @signup |
| Test ID | @PROV-E2E-001, @SCAN-E2E-002 |
Prowler Test Documentation Template
Keep under 60 lines. Focus on flow, preconditions, expected results only.
### 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}
Commands
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
Resources
- Documentation: See references/ for links to local developer guide
Frequently asked questions about Prowler Test UI
Similar skills
Spring Boot Testing
Master testing techniques for Spring Boot 4 applications.
GitHub Issues
Manage GitHub issues efficiently with MCP tools.
Geofeed Tuner
Optimize your IP geolocation feeds in CSV format.
Batch Files
Master Windows batch scripting for automation and task management.
Adobe Illustrator Scripting
Automate your Illustrator workflows with ExtendScript.
Plugin Structure
Create and organize Claude Code plugins effectively.
