All skills
sergiodxa avatar

/frontend-testing-best-practices

@4d1d816

Testing best practices for the frontend. Emphasizes E2E tests over unit tests, minimal mocking, and testing behavior over implementation details. Use when writing tests or reviewing test code.

Use this Skill: https://skilld.dev/gh/sergiodxa/agent-skills/frontend-testing-best-practices

This session only. Nothing lands on disk.

rulesunit-test-structure.md

≈873 tokens on demand. Your agent reads this file only when SKILL.md points to it.

Unit Test Structure

Structure unit tests for pure functions and utilities.

When to Write Unit Tests

Only write unit tests for:

  • Pure utility functions (formatCurrency, parseDate)
  • Data transformations and validators
  • Complex algorithms
  • Custom hooks with non-trivial logic (rare)

Basic Structure

import { describe, test, expect } from "vitest";
import { formatCurrency, formatPercentage } from "./format";

describe("formatCurrency", () => {
  test("formats positive amounts with two decimals", () => {
    expect(formatCurrency(1234.5)).toBe("$1,234.50");
  });

  test("formats zero", () => {
    expect(formatCurrency(0)).toBe("$0.00");
  });

  test("formats negative amounts", () => {
    expect(formatCurrency(-100)).toBe("-$100.00");
  });
});

describe("formatPercentage", () => {
  test("formats decimal as percentage", () => {
    expect(formatPercentage(0.25)).toBe("25%");
  });
});

Parameterized Tests

Use arrays for testing multiple inputs:

import { describe, test, expect } from "vitest";
import { slugify } from "./string";

const testCases: [string, string][] = [
  ["Hello World", "hello-world"],
  ["Multiple   Spaces", "multiple-spaces"],
  ["Special @#$ Characters", "special-characters"],
  ["Already-slugified", "already-slugified"],
  ["", ""],
];

describe("slugify", () => {
  test.each(testCases)('slugify("%s") returns "%s"', (input, expected) => {
    expect(slugify(input)).toBe(expected);
  });
});

Testing Error Cases

import { describe, test, expect } from "vitest";
import { parseAmount } from "./parse";

describe("parseAmount", () => {
  test("throws for invalid input", () => {
    expect(() => parseAmount("not-a-number")).toThrow("Invalid amount");
  });

  test("throws for negative amounts", () => {
    expect(() => parseAmount("-100")).toThrow("Amount must be positive");
  });
});

Testing Async Functions

import { describe, test, expect } from "vitest";
import { fetchUserData } from "./api";

describe("fetchUserData", () => {
  test("returns user data for valid ID", async () => {
    let user = await fetchUserData("user-123");
    expect(user).toEqual({
      id: "user-123",
      name: expect.any(String),
    });
  });

  test("throws for non-existent user", async () => {
    await expect(fetchUserData("invalid")).rejects.toThrow("User not found");
  });
});

File Naming and Location

Tests are co-located with source files:

app/
├── utils/
│   ├── format.ts
│   ├── format.test.ts      # Unit test
│   ├── string.ts
│   └── string.test.ts

Test Naming

Use descriptive names that explain the scenario:

// Bad: vague names
test("works", () => {});
test("test 1", () => {});
test("formatCurrency", () => {});

// Good: describes behavior
test("formats amount with thousand separators", () => {});
test("returns empty string for null input", () => {});
test("throws when amount exceeds maximum", () => {});

Rules

  1. Test file goes next to source file: foo.ts → foo.test.ts
  2. Use describe to group related tests
  3. Use descriptive test names that explain the expected behavior
  4. Test edge cases: null, undefined, empty, negative, max values
  5. Use test.each for parameterized tests with multiple inputs
  6. Keep tests focused - one assertion per behavior

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill provides a set of best practices and guidelines for frontend testing, focusing on E2E tests with Playwright and unit tests with Vitest. No security issues were detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    7 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 4d1d816. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Dormantupdated 8 months ago
  • Testing
  • React
  • e2e-testing
  • playwright
  • vitest
  • behavior-testing
  • mocking
  • unit-tests
  • test-strategy

README badge

README badge for sergiodxa/agent-skills/frontend-testing-best-practices

Provides guidelines for frontend testing that prioritize end-to-end tests over unit tests, minimize mocking, and test user behavior rather than implementation details. Use when writing or reviewing test code for web applications built with Playwright and Vitest.

Generated from the current SKILL.md.

When should I write unit tests vs E2E tests?
Default to E2E tests for user workflows and features. Only write unit tests for pure functions. If you need 3 or more mocks for a unit test, write an E2E test instead.
Should I test React components directly?
No. Test components through E2E tests that exercise them in a real user flow, rather than isolated component unit tests.
What selectors should I use in E2E tests?
Prefer accessible selectors in this order: role-based (getByRole), label-based (getByLabel), text-based, then test IDs. Avoid CSS selectors.
What testing tools does this skill assume?
E2E tests use Playwright, unit tests use Vitest. MSW (Mock Service Worker) is used for simple API mocking.

Generated from the current SKILL.md. These answers refresh after source changes.