framework-compliance-t…
Make a cloud account compliant with a security or industry framework using Prowler Cloud.
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).
$ npx -y skills add prowler-cloud/prowler --skill prowler-test-ui --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/prowler-test-uiContext preview
The summary Claude sees to decide when to auto-load this skill.
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).
name: prowler-test-ui
description: >
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).
license: Apache-2.0
metadata:
author: prowler-cloud
version: "1.0"
scope: [root, ui]
auto_invoke:
- "Writing Prowler UI E2E tests"
- "Working with Prowler UI test helpers/pages"
allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task> **Generic Patterns**: For base Playwright patterns (Page Object Model, selectors, helpers), see the `playwright` skill. > This skill covers **Prowler-specific** conventions only.
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)---
**⚠️ ALWAYS verify BEFORE completing any E2E task:**
# 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 `.md` file.
---
**⚠️ MANDATORY: If Playwright MCP tools are available, ALWAYS use them BEFORE creating tests.**
1. **Navigate** to target page 2. **Take snapshot** to see actual DOM structure 3. **Interact** with forms/elements to verify real flow 4. **Document actual selectors** from snapshots 5. **Only then** write test code
**Why**: Prevents tests based on assumptions. Real exploration = stable tests.
---
**⚠️ 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---
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 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.
---
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("/scanProwler is the world’s most widely used Open-Source Cloud Security Platform that automates security and compliance across any cloud environment.
Repo: prowler-cloud/prowler
Make a cloud account compliant with a security or industry framework using Prowler Cloud.
Vercel AI SDK 5 patterns. Trigger: When building AI features with AI SDK v5 (chat, streaming, tools/function calling, UIMessage parts), including migration…
Django REST Framework patterns. Trigger: When implementing generic DRF APIs (ViewSets, serializers, routers, permissions, filtersets). For Prowler API…
Reviews Django migration files for PostgreSQL best practices specific to Prowler. Trigger: When creating migrations, running makemigrations/pgmakemigrations,…
Create and maintain GitHub Agentic Workflows (gh-aw) for Prowler. Trigger: When creating agentic workflows, modifying gh-aw frontmatter, configuring…
Strict JSON:API v1.1 specification compliance. Trigger: When creating or modifying API endpoints, reviewing API responses, or validating JSON:API compliance.