⚠️ If you have Playwright MCP tools, ALWAYS use them BEFORE creating any test:
Navigate to target page
Take snapshot to see page structure and elements
Interact with forms/elements to verify exact user flow
Take screenshots to document expected states
Verify page transitions through complete flow (loading, success, error)
Document actual selectors from snapshots (use real refs and labels)
Only after exploring create test code with verified selectors
If MCP NOT available: Proceed with test creation based on docs and code analysis.
Why This Matters:
✅ Precise tests - exact steps needed, no assumptions
✅ Accurate selectors - real DOM structure, not imagined
✅ Real flow validation - verify journey actually works
✅ Avoid over-engineering - minimal tests for what exists
✅ Prevent flaky tests - real exploration = stable tests
❌ Never assume how UI "should" work
File Structure
tests/
├── base-page.ts # Parent class for ALL pages
├── helpers.ts # Shared utilities
└── {page-name}/
├── {page-name}-page.ts # Page Object Model
├── {page-name}.spec.ts # ALL tests here (NO separate files!)
└── {page-name}.md # Test documentation
File Naming:
✅ sign-up.spec.ts (all sign-up tests)
✅ sign-up-page.ts (page object)
✅ sign-up.md (documentation)
❌ sign-up-critical-path.spec.ts (WRONG - no separate files)
❌ sign-up-validation.spec.ts (WRONG)
Selector Priority (REQUIRED)
// 1. BEST - getByRole for interactive elements
this.submitButton = page.getByRole("button", { name: "Submit" });
this.navLink = page.getByRole("link", { name: "Dashboard" });
// 2. BEST - getByLabel for form controls
this.emailInput = page.getByLabel("Email");
this.passwordInput = page.getByLabel("Password");
// 3. SPARINGLY - getByText for static content only
this.errorMessage = page.getByText("Invalid credentials");
this.pageTitle = page.getByText("Welcome");
// 4. LAST RESORT - getByTestId when above fail
this.customWidget = page.getByTestId("date-picker");
// ❌ AVOID fragile selectors
this.button = page.locator(".btn-primary"); // NO
this.input = page.locator("#email"); // NO
Scope Detection (ASK IF AMBIGUOUS)
User Says
Action
"a test", "one test", "new test", "add test"
Create ONE test() in existing spec
"comprehensive tests", "all tests", "test suite", "generate tests"
Create full suite
Examples:
"Create a test for user sign-up" → ONE test only
"Generate E2E tests for login page" → Full suite
"Add a test to verify form validation" → ONE test to existing spec
npx playwright test # Run all
npx playwright test --grep "login" # Filter by name
npx playwright test --ui # Interactive UI
npx playwright test --debug # Debug mode
npx playwright test tests/login/ # Run specific folder
Prowler-Specific Patterns
For Prowler UI E2E testing with authentication setup, environment variables, and test IDs, see: