askill
agentic-jumpstart-testing

agentic-jumpstart-testingSafety 95Repository

Testing patterns with Playwright for E2E tests and Vitest for unit tests. Use when writing tests, testing components, E2E testing, integration tests, mocking, or when the user mentions testing, Playwright, Vitest, test, or coverage.

0 stars
1.2k downloads
Updated 1/20/2026

Package Files

Loading files...
SKILL.md

Testing Patterns

Playwright E2E Testing

Test Structure

// tests/courses.spec.ts
import { test, expect } from "@playwright/test";

test.describe("Courses", () => {
  test.beforeEach(async ({ page }) => {
    // Setup before each test
    await page.goto("/courses");
  });

  test("should display course list", async ({ page }) => {
    await expect(page.getByRole("heading", { name: "Courses" })).toBeVisible();
    await expect(page.getByTestId("course-card")).toHaveCount.greaterThan(0);
  });

  test("should navigate to course details", async ({ page }) => {
    await page.getByTestId("course-card").first().click();
    await expect(page).toHaveURL(/\/courses\/\d+/);
    await expect(page.getByRole("heading", { level: 1 })).toBeVisible();
  });
});

Authentication in Tests

// tests/auth.setup.ts
import { test as setup, expect } from "@playwright/test";

const authFile = "playwright/.auth/user.json";

setup("authenticate", async ({ page }) => {
  // Login flow
  await page.goto("/login");
  await page.getByLabel("Email").fill("test@example.com");
  await page.getByLabel("Password").fill("password");
  await page.getByRole("button", { name: "Sign In" }).click();

  // Wait for login to complete
  await expect(page).toHaveURL("/dashboard");

  // Save authentication state
  await page.context().storageState({ path: authFile });
});

// In playwright.config.ts
export default defineConfig({
  projects: [
    { name: "setup", testMatch: /.*\.setup\.ts/ },
    {
      name: "authenticated",
      testMatch: /.*\.spec\.ts/,
      dependencies: ["setup"],
      use: { storageState: authFile },
    },
  ],
});

Testing Protected Routes

test.describe("Admin Dashboard", () => {
  test.use({ storageState: "playwright/.auth/admin.json" });

  test("should access admin dashboard", async ({ page }) => {
    await page.goto("/admin");
    await expect(page.getByRole("heading", { name: "Admin Dashboard" })).toBeVisible();
  });
});

Page Object Pattern

// tests/pages/CoursePage.ts
import { Page, Locator } from "@playwright/test";

export class CoursePage {
  readonly page: Page;
  readonly title: Locator;
  readonly enrollButton: Locator;
  readonly moduleList: Locator;

  constructor(page: Page) {
    this.page = page;
    this.title = page.getByRole("heading", { level: 1 });
    this.enrollButton = page.getByRole("button", { name: "Enroll" });
    this.moduleList = page.getByTestId("module-list");
  }

  async goto(courseId: string) {
    await this.page.goto(`/courses/${courseId}`);
  }

  async enroll() {
    await this.enrollButton.click();
    await this.page.waitForURL(/\/checkout/);
  }

  async getModuleCount() {
    return this.moduleList.getByTestId("module-item").count();
  }
}

// Usage in test
test("should enroll in course", async ({ page }) => {
  const coursePage = new CoursePage(page);
  await coursePage.goto("1");
  await coursePage.enroll();
  await expect(page).toHaveURL(/\/checkout/);
});

Testing Forms

test("should submit contact form", async ({ page }) => {
  await page.goto("/contact");

  // Fill form
  await page.getByLabel("Name").fill("John Doe");
  await page.getByLabel("Email").fill("john@example.com");
  await page.getByLabel("Message").fill("Test message");

  // Submit
  await page.getByRole("button", { name: "Submit" }).click();

  // Verify success
  await expect(page.getByText("Message sent successfully")).toBeVisible();
});

Testing Async Operations

test("should load data", async ({ page }) => {
  await page.goto("/dashboard");

  // Wait for network request
  const responsePromise = page.waitForResponse("**/api/stats");
  await page.getByRole("button", { name: "Refresh" }).click();
  await responsePromise;

  // Verify data is displayed
  await expect(page.getByTestId("stats-card")).toBeVisible();
});

Visual Testing

test("should match visual snapshot", async ({ page }) => {
  await page.goto("/landing");
  await expect(page).toHaveScreenshot("landing-page.png");
});

Vitest Unit Testing

Testing Utility Functions

// src/utils/format.test.ts
import { describe, it, expect } from "vitest";
import { formatCurrency, formatDate, truncate } from "./format";

describe("formatCurrency", () => {
  it("should format USD currency", () => {
    expect(formatCurrency(1234.56)).toBe("$1,234.56");
  });

  it("should handle zero", () => {
    expect(formatCurrency(0)).toBe("$0.00");
  });
});

describe("truncate", () => {
  it("should truncate long strings", () => {
    expect(truncate("Hello World", 5)).toBe("Hello...");
  });

  it("should not truncate short strings", () => {
    expect(truncate("Hi", 10)).toBe("Hi");
  });
});

Testing Hooks

// src/hooks/useDebounce.test.ts
import { describe, it, expect, vi } from "vitest";
import { renderHook, act } from "@testing-library/react";
import { useDebounce } from "./useDebounce";

describe("useDebounce", () => {
  it("should debounce value updates", async () => {
    vi.useFakeTimers();

    const { result, rerender } = renderHook(
      ({ value }) => useDebounce(value, 500),
      { initialProps: { value: "initial" } }
    );

    expect(result.current).toBe("initial");

    rerender({ value: "updated" });
    expect(result.current).toBe("initial");

    act(() => {
      vi.advanceTimersByTime(500);
    });

    expect(result.current).toBe("updated");

    vi.useRealTimers();
  });
});

Mocking

import { describe, it, expect, vi, beforeEach } from "vitest";
import { processPayment } from "./payment";

// Mock external module
vi.mock("stripe", () => ({
  default: vi.fn().mockImplementation(() => ({
    paymentIntents: {
      create: vi.fn().mockResolvedValue({ id: "pi_123", status: "succeeded" }),
    },
  })),
}));

describe("processPayment", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("should process payment successfully", async () => {
    const result = await processPayment({ amount: 1000, currency: "usd" });
    expect(result.status).toBe("succeeded");
  });
});

Testing React Components

// src/components/Button.test.tsx
import { describe, it, expect, vi } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { Button } from "./Button";

describe("Button", () => {
  it("should render children", () => {
    render(<Button>Click me</Button>);
    expect(screen.getByRole("button")).toHaveTextContent("Click me");
  });

  it("should call onClick handler", () => {
    const handleClick = vi.fn();
    render(<Button onClick={handleClick}>Click</Button>);

    fireEvent.click(screen.getByRole("button"));
    expect(handleClick).toHaveBeenCalledTimes(1);
  });

  it("should be disabled when loading", () => {
    render(<Button disabled>Loading</Button>);
    expect(screen.getByRole("button")).toBeDisabled();
  });
});

Test Commands

# Run Playwright E2E tests
npm run test

# Run Playwright in headed mode
npm run test:headed

# Run Playwright with UI
npm run test:ui

# Run specific browser
npm run test:chrome
npm run test:firefox
npm run test:mobile

# Run Vitest unit tests
npm run test:unit

# Run Vitest in watch mode
npm run test:unit:watch

# Run Vitest with coverage
npm run test:unit:coverage

Test Data Setup

// tests/setup/database.ts
import { database } from "~/db";
import { users, courses } from "~/db/schema";

export async function seedTestData() {
  // Clear existing data
  await database.delete(courses);
  await database.delete(users);

  // Insert test user
  const [testUser] = await database
    .insert(users)
    .values({
      email: "test@example.com",
      name: "Test User",
    })
    .returning();

  // Insert test courses
  await database.insert(courses).values([
    { title: "Test Course 1", authorId: testUser.id },
    { title: "Test Course 2", authorId: testUser.id },
  ]);

  return { testUser };
}

Testing Checklist

  • E2E tests cover critical user flows
  • Authentication tests verify protected routes
  • Forms are tested with valid and invalid input
  • Page objects used for complex pages
  • Unit tests for utility functions
  • Mocks used for external services
  • Tests run in CI/CD pipeline
  • Test data is isolated between tests
  • Visual snapshots for critical pages
  • Coverage reports generated

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

87/100Analyzed 2/19/2026

High-quality testing skill covering Playwright E2E and Vitest unit testing with extensive code examples. Has clear trigger conditions, structured patterns (page objects, auth setup, mocking), and comprehensive test commands. Located in dedicated skills folder with good tags. Content is generic and reusable despite slightly project-specific path. Scores well on actionability, clarity, and completeness."

95
90
85
85
90

Metadata

Licenseunknown
Version-
Updated1/20/2026
Publisherdamandeep611

Tags

apici-cddatabasesecuritytesting