home / skills / prowler-cloud / prowler / prowler-test-ui

prowler-test-ui skill

/skills/prowler-test-ui

This skill helps write reliable Playwright end-to-end tests for the Prowler UI using base patterns, MCP workflow, and page objects.

npx playbooks add skill prowler-cloud/prowler --skill prowler-test-ui

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
5.1 KB
---
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.

## 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
```

---

## MCP Workflow - CRITICAL

**⚠️ 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.

---

## Prowler Base Page

```typescript
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);
    await this.page.waitForLoadState("networkidle");
  }

  async waitForPageLoad(): Promise<void> {
    await this.page.waitForLoadState("networkidle");
  }

  // 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);
  }
}
```

---

## Prowler-Specific Pages

### Providers Page

```typescript
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

```typescript
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

```typescript
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.**

```markdown
### 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

```bash
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/](references/) for links to local developer guide

Overview

This skill documents Prowler-specific Playwright E2E testing patterns and conventions for tests under ui/tests. It focuses on the Prowler base page, page objects, mandatory MCP workflow, tagging standards, and a compact test documentation template. Use it to create consistent, stable, and discoverable UI tests for Prowler features.

How this skill works

It prescribes a project layout with a Prowler base page, helpers, one spec per feature, and per-page page objects. It enforces the MCP workflow: inspect the live DOM with Playwright tools, capture snapshots, interact to confirm flows, document selectors, then write tests. It also provides Prowler-specific helper methods (notifications, navigation) and example page classes for Providers and Scans.

When to use it

  • When writing new Playwright E2E tests under ui/tests for Prowler UI features
  • When updating tests after UI changes to verify selectors and flows
  • When creating page objects that depend on Prowler-specific behaviors (notifications, networkidle waits)
  • When tagging test cases to match Prowler conventions for priority, type, feature, and test ID
  • When authoring short test documentation per feature using the provided template

Best practices

  • Always run the MCP workflow with Playwright tools before coding tests to avoid brittle selectors
  • Keep one spec file per feature and a single page object file per page for clarity
  • Use the Prowler BasePage methods for navigation and notification handling to standardize waits
  • Tag tests with priority, type, feature, and a stable test ID to enable filtering and reporting
  • Limit documentation to the provided template: concise preconditions, flow steps, and key verifications

Example use cases

  • Add an E2E test for provider CRUD operations using ProvidersPage.addProvider and table assertions
  • Create a scan-launching test using ScansPage.startScan and verify notification messages via BasePage.verifyNotificationMessage
  • Investigate a flaky selector by taking MCP snapshots, updating selector in the page object, and re-running tests
  • Batch-run only provider-related tests with tags like @providers and @PROV-E2E-001 for quick validation
  • Document a new feature test case with the template to keep expectations and verification points clear

FAQ

What is the MCP workflow and why is it mandatory?

MCP stands for navigate, snapshot, interact, and document. It ensures tests are built from the real DOM and flows, reducing assumptions and flakiness.

Where should notification assertions live?

Use BasePage.waitForNotification and verifyNotificationMessage so all notification handling is centralized and consistent.