From shipshitdev-library
Initializes Playwright for E2E testing in Next.js and React projects: installs deps, creates config/tests, adds scripts, integrates CI/CD. Use when adding E2E tests to frontend apps.
npx claudepluginhub shipshitdev/skillsThis skill uses the workspace's default tool permissions.
Sets up Playwright for end-to-end testing in Next.js and React applications.
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
Analyzes competition with Porter's Five Forces, Blue Ocean Strategy, and positioning maps to identify differentiation opportunities and market positioning for startups and pitches.
Sets up Playwright for end-to-end testing in Next.js and React applications.
This skill should be used when:
Example prompt:
Add Playwright E2E tests to this project
Or be specific:
Set up E2E tests for the authentication flow
bun add -D @playwright/test
bunx playwright install chromium
import { defineConfig, devices } from "@playwright/test";
export default defineConfig({
testDir: "./e2e",
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [["html", { open: "never" }], ["list"]],
use: {
baseURL: "http://localhost:3000",
trace: "on-first-retry",
screenshot: "only-on-failure",
},
projects: [
{ name: "chromium", use: { ...devices["Desktop Chrome"] } },
],
webServer: {
command: "bun run dev",
url: "http://localhost:3000",
reuseExistingServer: !process.env.CI,
timeout: 120 * 1000,
},
});
e2e/
├── home.spec.ts # Homepage tests
├── auth.spec.ts # Authentication flow
├── navigation.spec.ts # Navigation tests
└── fixtures/
└── test-data.ts # Shared test data
import { test, expect } from "@playwright/test";
test.describe("Homepage", () => {
test("should load successfully", async ({ page }) => {
await page.goto("/");
await expect(page).toHaveTitle(/My App/);
});
test("should navigate to about page", async ({ page }) => {
await page.goto("/");
await page.click('a[href="/about"]');
await expect(page).toHaveURL("/about");
});
});
import { test, expect } from "@playwright/test";
test.describe("Authentication", () => {
test("should login successfully", async ({ page }) => {
await page.goto("/login");
await page.fill('input[name="email"]', "test@example.com");
await page.fill('input[name="password"]', "password123");
await page.click('button[type="submit"]');
await expect(page).toHaveURL("/dashboard");
await expect(page.locator("text=Welcome")).toBeVisible();
});
test("should show error for invalid credentials", async ({ page }) => {
await page.goto("/login");
await page.fill('input[name="email"]', "wrong@example.com");
await page.fill('input[name="password"]', "wrongpassword");
await page.click('button[type="submit"]');
await expect(page.locator("text=Invalid credentials")).toBeVisible();
});
});
import { test, expect } from "@playwright/test";
test.describe("Contact Form", () => {
test("should submit form successfully", async ({ page }) => {
await page.goto("/contact");
await page.fill('input[name="name"]', "John Doe");
await page.fill('input[name="email"]', "john@example.com");
await page.fill('textarea[name="message"]', "Hello, this is a test message");
await page.click('button[type="submit"]');
await expect(page.locator("text=Thank you")).toBeVisible();
});
});
Add to package.json:
{
"scripts": {
"e2e": "playwright test",
"e2e:ui": "playwright test --ui",
"e2e:headed": "playwright test --headed",
"e2e:debug": "playwright test --debug",
"e2e:report": "playwright show-report"
}
}
Add to your CI workflow:
- name: Install Playwright Browsers
run: bunx playwright install --with-deps chromium
- name: Run E2E tests
run: bun run e2e
env:
CI: true
- name: Upload Playwright Report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 7
Focus on:
// e2e/pages/login.page.ts
import { Page } from "@playwright/test";
export class LoginPage {
constructor(private page: Page) {}
async goto() {
await this.page.goto("/login");
}
async login(email: string, password: string) {
await this.page.fill('input[name="email"]', email);
await this.page.fill('input[name="password"]', password);
await this.page.click('button[type="submit"]');
}
}
<button data-testid="submit-button">Submit</button>
await page.click('[data-testid="submit-button"]');
Each test should:
import { test as base } from "@playwright/test";
const test = base.extend({
authenticatedPage: async ({ page }, use) => {
await page.goto("/login");
await page.fill('input[name="email"]', "test@example.com");
await page.fill('input[name="password"]', "password");
await page.click('button[type="submit"]');
await use(page);
},
});
Increase timeout in config:
timeout: 60000, // 60 seconds
Use waitFor:
await page.waitForSelector('[data-testid="element"]');
Add retries and use toPass:
await expect(async () => {
await expect(page.locator("text=Success")).toBeVisible();
}).toPass({ timeout: 10000 });
| Skill | Integration |
|---|---|
testing-cicd-init | Sets up unit tests first |
testing-expert | Provides testing patterns |
debug | Investigates flaky tests and failing browser flows |
When this skill is active, it will: