From memstack
Generates Playwright end-to-end browser tests for web app user flows. Activates on 'write browser tests', 'playwright test', 'e2e test', 'test the UI' requests.
npx claudepluginhub cwinvestments/memstack --plugin memstackThis skill uses the workspace's default tool permissions.
*Produces Playwright end-to-end tests that verify real user flows in a browser.*
Guides Playwright end-to-end testing for web apps with cross-browser support (Chromium, Firefox, WebKit), visual regression, API testing, and mobile emulation. Use for E2E tests and UI automation workflows.
Guides Playwright E2E testing with browser automation, auto-wait locators, page objects, cross-browser projects, CI configs, and debugging traces.
Provides patterns for reliable Playwright E2E tests in web apps, covering locators, authentication, forms (React/SPA), assertions, organization, reliability, and CI/CD. Use for writing, reviewing, or debugging tests.
Share bugs, ideas, or general feedback.
Produces Playwright end-to-end tests that verify real user flows in a browser.
| Trigger | Status |
|---|---|
| User says "write browser tests" or "playwright test" | ACTIVE |
| User says "test this page" or "e2e test" | ACTIVE |
| User says "test the UI" or "browser test" | ACTIVE |
| User wants unit tests or API tests | NOT this skill — use standard test patterns |
| User wants load testing | NOT this skill |
Determine what to test:
| Parameter | How to find | Example |
|---|---|---|
| App URL | Check package.json scripts, .env, or ask | http://localhost:3000 |
| Framework | Check package.json dependencies | Next.js, React, SvelteKit |
| Auth required? | Check for login pages, auth middleware | Yes/No |
| Key user flows | Ask or infer from routes | Sign up, checkout, search |
# Check if Playwright is already installed
cat package.json | grep -i playwright
# Check existing test structure
find . -name "*.spec.ts" -o -name "*.test.ts" | head -20
npm init playwright@latest
# or
pnpm add -D @playwright/test
npx playwright install
Confirm playwright.config.ts exists. If not, create with sensible defaults:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
],
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
});
Follow this structure per flow:
import { test, expect } from '@playwright/test';
test.describe('Feature Name', () => {
test('should [expected behavior] when [action]', async ({ page }) => {
// Arrange — navigate to the page
await page.goto('/path');
// Act — perform user actions
await page.getByRole('button', { name: 'Submit' }).click();
// Assert — verify the result
await expect(page.getByText('Success')).toBeVisible();
});
});
Test writing rules:
getByRole, getByLabel, getByText over CSS selectors — they survive refactorstest.describe to group related flowstest.beforeEach for shared navigation/auth setupexpect with auto-waiting or waitForSelectorIf the app requires login:
// tests/e2e/auth.setup.ts
import { test as setup, expect } from '@playwright/test';
setup('authenticate', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('test@example.com');
await page.getByLabel('Password').fill('testpassword');
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page).toHaveURL('/dashboard');
// Save signed-in state
await page.context().storageState({ path: '.auth/user.json' });
});
Add to playwright.config.ts:
projects: [
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
storageState: '.auth/user.json',
},
dependencies: ['setup'],
},
],
Form validation:
test('should show validation errors for empty required fields', async ({ page }) => {
await page.goto('/form');
await page.getByRole('button', { name: 'Submit' }).click();
await expect(page.getByText('Email is required')).toBeVisible();
});
Navigation flow:
test('should navigate from landing to pricing', async ({ page }) => {
await page.goto('/');
await page.getByRole('link', { name: 'Pricing' }).click();
await expect(page).toHaveURL('/pricing');
await expect(page.getByRole('heading', { name: 'Pricing' })).toBeVisible();
});
API response verification:
test('should load and display data', async ({ page }) => {
await page.goto('/dashboard');
await expect(page.getByRole('table')).toBeVisible();
await expect(page.locator('tbody tr')).toHaveCount(10);
});
# Run all tests
npx playwright test
# Run specific test file
npx playwright test tests/e2e/auth.spec.ts
# Run with UI mode for debugging
npx playwright test --ui
# Show HTML report
npx playwright show-report
Present results:
Playwright tests written:
- [N] test files covering [N] user flows
- Auth setup: [yes/no]
- Flows tested: [list]
Run with: npx playwright test