prowler-test-ui
Provides E2E testing conventions for the Prowler UI, including required documentation and Playwright helpers.
Install
mkdir -p .claude/skills/prowler-test-ui && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/7233" && unzip -o skill.zip -d .claude/skills/prowler-test-ui && rm skill.zipInstalls to .claude/skills/prowler-test-ui
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
E2E testing patterns for Prowler UI (Playwright). Trigger: When writing Playwright E2E tests under ui/tests in the Prowler UI (Prowler-specific base page/helpers, tags, flows).Key capabilities
- →Generate Playwright Page Object Models
- →Synchronize.spec.ts tags with.md documentation
- →Apply base-page helpers for Prowler UI
- →Validate E2E test IDs across documentation and code
How it works
It enforces a rigid file structure where every Playwright spec must have a matching documentation file, verifying test IDs and tags in both.
Inputs & outputs
When to use prowler-test-ui
- →Writing Playwright tests for Prowler UI
- →Synchronizing test documentation with spec files
- →Implementing Prowler base page helpers
About this skill
Generic 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
When not to use it
- →Backend API or SDK unit testing
- →Manual QA testing
Prerequisites
Limitations
- →Documentation must be manually updated to mirror code
- →Strict directory layout required
How it compares
It makes test documentation a hard dependency for build completion, preventing stale test records.
Compared to similar skills
prowler-test-ui side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| prowler-test-ui (this skill) | 1 | 2mo | Review | Intermediate |
| ui-ux-expert-skill | 91 | 9mo | Review | Advanced |
| playwright-browser-automation | 29 | 7mo | Review | Intermediate |
| frontend-testing | 11 | 3mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by prowler-cloud
View all by prowler-cloud →You might also like
ui-ux-expert-skill
fercracix33
Technical workflow for implementing accessible React user interfaces with shadcn/ui, Tailwind CSS, and TanStack Query. Includes 6-phase process with mandatory Style Guide compliance, Context7 best practices consultation, Chrome DevTools validation, and WCAG 2.1 AA accessibility standards. Use after Test Agent, Implementer, and Supabase agents complete their work.
playwright-browser-automation
lackeyjb
Complete browser automation with Playwright. Auto-detects dev servers, writes clean test scripts to /tmp. Test pages, fill forms, take screenshots, check responsive design, validate UX, test login flows, check links, automate any browser task. Use when user wants to test websites, automate browser interactions, validate web functionality, or perform any browser-based testing.
frontend-testing
langgenius
Generate Vitest + React Testing Library tests for Dify frontend components, hooks, and utilities. Triggers on testing, spec files, coverage, Vitest, RTL, unit tests, integration tests, or write/review test requests.
flutter
alinaqi
Flutter development with Riverpod state management, Freezed, go_router, and mocktail testing
feature-flags
Use when feature flag tests fail, flags need updating, understanding @gate pragmas, debugging channel-specific test failures, or adding new flags to React.
vue-testing-best-practices
vuejs-ai
Use for Vue.js testing. Covers Vitest, Vue Test Utils, component testing, mocking, testing patterns, and Playwright for E2E testing.