<< All versions
Skill v1.0.2
currentAutomated scan100/100raheesahmed/sajicode/testing
~2 modified
──Details
PublishedJuly 22, 2026 at 01:39 PM
Content Hashsha256:267fbc684dda3a87...
Git SHA791249e54ef4
Bump Typepatch
──Files
Files (1 file, 6.2 KB)
SKILL.md6.2 KBactive
SKILL.md · 209 lines · 6.2 KB
version: "1.0.2" name: testing description: Design and implement comprehensive test suites. Covers unit testing, integration testing, E2E testing with Playwright, API testing, mocking strategies, test data factories, TDD workflow, snapshot testing, coverage targets, and CI integration. Use when writing tests, designing test architecture, or debugging test failures.
Advanced Testing
Test Architecture
Test Pyramid
/ E2E \ ← Few: critical user flows only/----------\/ Integration \ ← Medium: API routes, DB queries/----------------\/ Unit Tests \ ← Many: business logic, utils, transforms
File Organization
src/├── services/│ ├── user-service.ts│ └── user-service.test.ts ← Colocated unit tests├── routes/│ ├── auth.ts│ └── auth.integration.test.ts ← Integration tests└── __tests__/└── e2e/└── auth-flow.spec.ts ← E2E tests
Unit Testing (Vitest / Jest)
Test Data Factory
ts
function createUser(overrides: Partial<User> = {}): User {return {id: crypto.randomUUID(),email: `user-${Date.now()}@test.com`,name: "Test User",role: "USER",createdAt: new Date(),updatedAt: new Date(),...overrides,};}function createPost(overrides: Partial<Post> = {}): Post {return {id: crypto.randomUUID(),title: "Test Post",content: "Test content for testing purposes.",published: false,authorId: crypto.randomUUID(),createdAt: new Date(),...overrides,};}
AAA Pattern with Edge Cases
ts
describe("UserService", () => {describe("createUser", () => {it("creates user with valid input", async () => {const input = { email: "valid@test.com", name: "Valid User" };const user = await userService.create(input);expect(user.id).toBeDefined();expect(user.email).toBe("valid@test.com");});it("throws on duplicate email", async () => {await userService.create({ email: "dup@test.com", name: "First" });await expect(userService.create({ email: "dup@test.com", name: "Second" })).rejects.toThrow("Email already exists");});it("trims and lowercases email", async () => {const user = await userService.create({ email: " UPPER@Test.COM ", name: "User" });expect(user.email).toBe("upper@test.com");});it("rejects empty name", async () => {await expect(userService.create({ email: "a@b.com", name: "" })).rejects.toThrow();});});});
Mocking Patterns
ts
// Mock external servicevi.mock("../lib/email", () => ({sendEmail: vi.fn().mockResolvedValue({ success: true }),}));// Mock with implementationconst mockFetch = vi.fn().mockImplementation((url: string) => {if (url.includes("/users/123")) {return Promise.resolve({ ok: true, json: () => Promise.resolve({ id: "123", name: "Test" }) });}return Promise.resolve({ ok: false, status: 404 });});// Spy on methodconst logSpy = vi.spyOn(logger, "error");await processOrder(invalidOrder);expect(logSpy).toHaveBeenCalledWith("Order processing failed", expect.any(Object));
API Integration Testing
ts
import { describe, it, expect, beforeAll, afterAll } from "vitest";import request from "supertest";import { app } from "../app";describe("POST /api/auth/register", () => {it("returns 201 with valid registration", async () => {const res = await request(app).post("/api/auth/register").send({ email: "new@test.com", password: "SecurePass123", name: "New User" }).expect(201);expect(res.body.data.user.email).toBe("new@test.com");expect(res.body.data.token).toBeDefined();expect(res.body.data.user.password).toBeUndefined(); // Never expose});it("returns 400 for weak password", async () => {await request(app).post("/api/auth/register").send({ email: "test@test.com", password: "weak", name: "User" }).expect(400);});it("returns 409 for duplicate email", async () => {await request(app).post("/api/auth/register").send({ email: "existing@test.com", password: "Pass123!", name: "User" });await request(app).post("/api/auth/register").send({ email: "existing@test.com", password: "Pass456!", name: "User2" }).expect(409);});});
E2E Testing (Playwright)
ts
import { test, expect } from "@playwright/test";test.describe("Authentication Flow", () => {test("user can register, login, and access dashboard", async ({ page }) => {await page.goto("/register");await page.getByLabel("Email").fill("e2e@test.com");await page.getByLabel("Password").fill("SecurePass123!");await page.getByLabel("Name").fill("E2E User");await page.getByRole("button", { name: "Register" }).click();await expect(page).toHaveURL("/dashboard");await expect(page.getByText("Welcome, E2E User")).toBeVisible();});test("shows error on invalid credentials", async ({ page }) => {await page.goto("/login");await page.getByLabel("Email").fill("wrong@test.com");await page.getByLabel("Password").fill("wrongpass");await page.getByRole("button", { name: "Sign in" }).click();await expect(page.getByText("Invalid credentials")).toBeVisible();await expect(page).toHaveURL("/login");});});
Coverage & CI
Coverage Targets
| Layer | Target | Strategy | |
|---|---|---|---|
| Business logic | 90%+ | Unit tests | |
| API routes | 80%+ | Integration tests | |
| UI components | 70%+ | Component tests | |
| E2E flows | Critical paths | Playwright |
CI Configuration
yaml
test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- uses: actions/setup-node@v4- run: npm ci- run: npm run test -- --coverage- run: npx playwright install --with-deps- run: npm run test:e2e
Rules
- Test behavior, not implementation details
- NEVER hardcode values to make tests pass — fix the code
- Use factories for test data — never raw objects
- Mock external dependencies — never real APIs in unit tests
- One concept per test — descriptive test names
- Clean up test data in
afterEach/afterAll