playwright-page-object-builder
Create maintainable and reusable Page Object Models (POMs) for Playwright tests. Generates TypeScript classes that encapsulate page-specific locators and actions, following the Page Object Model design pattern with data-testid locators exclusively.
What this skill does
## When to Use This Skill
Use this skill when you need to:
- Create a Page Object Model for a specific page or component
- Refactor tests to use the POM pattern
- Build reusable page classes for complex applications
- Encapsulate page-specific logic and locators
- Improve test maintainability and reduce duplication
Do NOT use this skill when:
- Writing simple one-off tests (use test-generator skill)
- Debugging existing tests (use test-debugger skill)
- Refactoring existing POMs (use test-maintainer skill)
## Prerequisites
Before using this skill:
1. Understanding of the page structure and elements
2. Knowledge of user interactions on the page
3. List of data-testid values for page elements (or ability to suggest them)
4. Playwright installed in the project
5. Basic understanding of TypeScript classes
## Instructions
### Step 1: Identify Page Information
Gather from the user:
- **Page name** or component name
- **Page URL** or route
- **Key elements** on the page (buttons, inputs, text, etc.)
- **Common actions** users perform on the page
- **data-testid values** for all elements (or help define them)
### Step 2: Plan Page Object Structure
Determine:
- **Class name** (e.g., `LoginPage`, `DashboardPage`, `CheckoutPage`)
- **Properties**: Locators for all page elements
- **Methods**: Actions users can perform (login, addToCart, etc.)
- **Getters**: Read-only properties for assertions
- **Navigation**: How to reach this page
### Step 3: Create Page Object Class
Generate a TypeScript class with:
**Structure:**
```typescript
import { Page, Locator } from "@playwright/test";
export class PageName {
readonly page: Page;
// Locators
readonly elementName: Locator;
constructor(page: Page) {
this.page = page;
this.elementName = page.locator('[data-testid="element-name"]');
}
// Navigation
async goto() {
await this.page.goto("/page-url");
}
// Actions
async performAction() {
await this.elementName.click();
}
// Getters for assertions
getElement() {
return this.elementName;
}
}
```
**Key Requirements:**
1. All locators use data-testid (MANDATORY)
2. Locators are readonly properties
3. Constructor accepts Page object
4. Include goto() method for navigation
5. Action methods are async and return Promise<void>
6. Getter methods for elements that need assertions
7. Use TypeScript types
8. Add JSDoc comments for complex methods
### Step 4: Define Locators
For each element:
```typescript
readonly elementName: Locator;
constructor(page: Page) {
this.page = page;
this.elementName = page.locator('[data-testid="element-name"]');
}
```
**Naming Convention:**
- Use camelCase for properties
- Descriptive names (e.g., `submitButton`, `emailInput`, `errorMessage`)
- Suffix with element type when helpful (Button, Input, Message, Link)
### Step 5: Implement Action Methods
For each user action:
```typescript
/**
* Descriptive action name
* @param param - Parameter description if needed
*/
async actionName(param?: string): Promise<void> {
// Wait for element if needed
await this.element.waitFor({ state: 'visible' });
// Perform action
await this.element.click();
// or
await this.element.fill(param);
}
```
**Common Actions:**
- Form filling: `async fillForm(data: FormData)`
- Button clicks: `async clickButton()`
- Navigation: `async navigateTo(section: string)`
- Complex workflows: `async completeCheckout(details: CheckoutDetails)`
### Step 6: Add Getter Methods
For elements that tests will assert against:
```typescript
getElementName(): Locator {
return this.elementName;
}
async getTextContent(): Promise<string> {
return await this.element.textContent() || '';
}
async isElementVisible(): Promise<boolean> {
return await this.element.isVisible();
}
```
### Step 7: Validate Page Object
Ensure the Page Object includes:
- [ ] All locators use data-testid
- [ ] Locators are readonly
- [ ] All methods are async
- [ ] Constructor accepts Page
- [ ] goto() method for navigation
- [ ] JSDoc comments for public methods
- [ ] TypeScript types for parameters
- [ ] Meaningful method names
- [ ] No test assertions in POM (only actions and getters)
### Step 8: Provide Usage Example
Show how to use the Page Object in tests:
```typescript
import { test, expect } from "@playwright/test";
import { PageName } from "./page-objects/PageName";
test("test description", async ({ page }) => {
const pageName = new PageName(page);
await pageName.goto();
await pageName.performAction();
await expect(pageName.getElement()).toBeVisible();
});
```
## Examples
### Example 1: Login Page Object
**Input:**
"Create a Page Object for the login page with username, password fields, login button, and error message."
**Output:**
```typescript
import { Page, Locator } from "@playwright/test";
/**
* Page Object Model for the Login Page
*
* Handles user authentication flow including:
* - Filling login credentials
* - Submitting the form
* - Accessing error messages
*/
export class LoginPage {
readonly page: Page;
// Locators
readonly usernameInput: Locator;
readonly passwordInput: Locator;
readonly loginButton: Locator;
readonly errorMessage: Locator;
readonly forgotPasswordLink: Locator;
constructor(page: Page) {
this.page = page;
this.usernameInput = page.locator('[data-testid="username-input"]');
this.passwordInput = page.locator('[data-testid="password-input"]');
this.loginButton = page.locator('[data-testid="login-button"]');
this.errorMessage = page.locator('[data-testid="error-message"]');
this.forgotPasswordLink = page.locator(
'[data-testid="forgot-password-link"]',
);
}
/**
* Navigate to the login page
*/
async goto(): Promise<void> {
await this.page.goto("/login");
await this.page.waitForLoadState("domcontentloaded");
}
/**
* Perform login with credentials
* @param username - User's username or email
* @param password - User's password
*/
async login(username: string, password: string): Promise<void> {
await this.usernameInput.waitFor({ state: "visible" });
await this.usernameInput.fill(username);
await this.passwordInput.fill(password);
await this.loginButton.click();
}
/**
* Fill only the username field
*/
async fillUsername(username: string): Promise<void> {
await this.usernameInput.fill(username);
}
/**
* Fill only the password field
*/
async fillPassword(password: string): Promise<void> {
await this.passwordInput.fill(password);
}
/**
* Click the login button
*/
async clickLogin(): Promise<void> {
await this.loginButton.click();
}
/**
* Click forgot password link
*/
async clickForgotPassword(): Promise<void> {
await this.forgotPasswordLink.click();
}
/**
* Get the error message element for assertions
*/
getErrorMessage(): Locator {
return this.errorMessage;
}
/**
* Check if error message is visible
*/
async hasError(): Promise<boolean> {
try {
await this.errorMessage.waitFor({ state: "visible", timeout: 2000 });
return true;
} catch {
return false;
}
}
/**
* Get the text content of the error message
*/
async getErrorText(): Promise<string> {
const text = await this.errorMessage.textContent();
return text?.trim() || "";
}
}
```
**Usage:**
```typescript
import { test, expect } from "@playwright/test";
import { LoginPage } from "./page-objects/LoginPage";
test.describe("Login Flow", () => {
test("should login successfully with valid credentials", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login("[email protected]", "SecurePass123");
// Assert navigation to dashboard
await page.waitForURL("/dashboard");
});
test("should show error with invalid credentials", async ({ page }) => {
const loginPage = new LoginPage(page);
awaRelated in Design
contribute
IncludedLocal-only OSS contribution command center. Auto-refreshes the user's in-flight PR and issue state on invoke so conversations start with full context — no need to brief Claude on what's in flight. Helps the user find issues to contribute to on GitHub, builds per-repo dossiers of what each upstream expects (CLA, DCO, branch convention, AI policy, draft-first, review bots, issue templates), runs deterministic gates before any external action so AI-assisted contributions don't reach maintainers as slop. State is markdown-only: candidate files at ~/.contribute-system/candidates/, repo dossiers at ~/.contribute-system/research/, append-only event log at ~/.contribute-system/log.jsonl. No database, no cloud calls. Use when the user asks about their PRs / issues / contributions, wants to find new work to take on, claim an issue, build/refresh a repo's dossier, or draft a Design Issue or PR. Trigger with "/contribute", "what's my PR status", "find a contribution", "claim issue X", "draft a Design Issue for Y", "refresh dossier for Z".
architectural-analysis
IncludedUser-triggered deep architectural analysis of a codebase or scoped subtree across eight modes — information architecture, data flow, integration points, UI surfaces, interaction patterns, data model, control flow, and failure modes. This skill should be used when the user asks to "diagram this codebase," "map the architecture," "show the data flow," "give me an ERD," "trace control flow," "find the integration points," "verify the layout pattern," "audit the UX architecture," or any similar request whose primary deliverable is mermaid diagrams plus cited reports under docs/architecture/. Dispatches haiku/sonnet sub-agents in parallel for per-mode exploration, then verifies every citation mechanically before any node lands in a diagram. Not for one-off prose explanations of code (use code-explanation) or for high-level system design from scratch (use system-design).
mcp
IncludedModel Context Protocol (MCP) server development and tool management. Languages: Python, TypeScript. Capabilities: build MCP servers, integrate external APIs, discover/execute MCP tools, manage multi-server configs, design agent-centric tools. Actions: create, build, integrate, discover, execute, configure MCP servers/tools. Keywords: MCP, Model Context Protocol, MCP server, MCP tool, stdio transport, SSE transport, tool discovery, resource provider, prompt template, external API integration, Gemini CLI MCP, Claude MCP, agent tools, tool execution, server config. Use when: building MCP servers, integrating external APIs as MCP tools, discovering available MCP tools, executing MCP capabilities, configuring multi-server setups, designing tools for AI agents.
react-native-skia
IncludedDesign, build, debug, and optimise high-polish animated graphics in React Native or Expo using @shopify/react-native-skia, Reanimated, and Gesture Handler. Use when the user wants canvas-driven UI, shaders, paths, rich text, image filters, sprite fields, Skottie, video frames, snapshots, web CanvasKit setup, or performance tuning for custom motion-heavy elements such as loaders, hero art, cards, charts, progress indicators, particle systems, or gesture-driven surfaces. Also use when the user asks for fluid, glow, glass, blob, parallax, 60fps/120fps, or GPU-friendly animated effects in React Native, even if they do not explicitly say "Skia". Do not use for ordinary form/layout work with standard views.
plaid
IncludedProduct Led AI Development — guides founders from idea to launched product. Six capabilities: Idea (discover a product idea), Validate (pressure-test the idea against fatal flaws, problem reality, competition, and 2-week MVP feasibility), Plan (vision intake + document generation), Design (translate image references into a design.md spec), Launch (go-to-market strategy), and Build (roadmap execution). Use when someone says "PLAID", "plaid idea", "help me find an idea", "product idea", "idea from my business", "idea from my expertise", "plaid validate", "validate my idea", "pressure-test", "is this idea good", "find fatal flaws", "validate the problem", "plan a product", "define my vision", "generate a PRD", "product strategy", "plaid design", "design from image", "translate image to design", "create design.md", "extract design tokens", "plaid launch", "go-to-market", "launch plan", "GTM strategy", "launch playbook", "plaid build", "build the app", "start building", or "execute the roadmap".
nextjs-framer-motion-animations
IncludedAdds production-safe Motion for React or Framer Motion animations to Next.js apps, including reveal, hover and tap micro-interactions, whileInView, stagger, AnimatePresence, layout and layoutId transitions, reorder, scroll-linked UI, and lightweight route-content transitions. Use when the user asks to add, refactor, or debug Motion or Framer Motion in App Router or Pages Router codebases, especially around server/client boundaries, reduced motion, LazyMotion, bundle size, hydration, or route transitions. Avoid for GSAP-style timelines, WebGL or 3D scenes, heavy scroll storytelling, or CSS-only effects unless Motion is explicitly requested.