Agent skill
web-testing
(ePost) Use when writing tests, configuring Jest/Playwright, checking coverage, or working with test patterns
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/web-testing-klara-copilot-epost-agent-kit
Metadata
Additional technical details for this skill
- keywords
-
test jest playwright coverage e2e unit-test rtl testing-library
- triggers
-
[ "test", "jest", "playwright", "coverage", "e2e", "unit test", "spec" ] - platforms
-
[ "web" ] - agent affinity
-
[ "epost-tester", "epost-fullstack-developer" ]
SKILL.md
Testing — Jest + Playwright Patterns
Purpose
Testing patterns for Next.js web applications. Covers Jest + React Testing Library for unit/component tests, Playwright for E2E, and test runner targets.
Test Structure
Tests live in a tests/ directory and mirror the app route structure:
app/[locale]/(auth)/feature-a/utils/mapping/mapping.ts
tests/[locale]/feature-a/utils/mapping/mapping.test.ts
app/[locale]/(auth)/hooks/sidebar/useSidebarBuilder.ts
tests/[locale]/hooks/useSidebarBuilder.test.ts
Jest Configuration
Project Config
Location: jest.config.ts
- Uses
next/jestwithts-jesttransform testEnvironment: 'jsdom'pathsToModuleNameMapperfromtsconfig.base.jsonfor path aliases@testing-library/jest-domloaded viasetupFilesAfterSetup- Global mocks for
IntersectionObserver,TextEncoder,TextDecoder,fetch - Custom
transformIgnorePatternsto whitelist ESM-only dependencies
Coverage
# Run tests
npm test -- --testFile=path/to/test.test.ts
npm test -- --coverage
Coverage is reported via lcov + jest-junit + jest-sonar-reporter. No enforced thresholds — coverage is tracked but not gated.
Unit Test Patterns
Mock Function Typing
jest.mock('../../caller/feature-caller');
jest.mock('../../app/[locale]/(auth)/feature-a/utils/image-util');
const mockGetLogo = getLogo as jest.MockedFunction<typeof getLogo>;
const mockGetDocumentById = getDocumentById as jest.MockedFunction<typeof getDocumentById>;
Mock Module with Factory
// Getter pattern for mutable config
const mockMenuConfig: any[] = [];
jest.mock('../../../app/[locale]/(auth)/config/menu-items.config', () => ({
get MENU_ITEMS_CONFIG() { return mockMenuConfig; },
}));
// Auto-mock with inline defaults
jest.mock('@app/service/feature-flag-service', () => ({
getFeatureFlagStatuses: jest.fn().mockResolvedValue(new Map()),
}));
Test Structure
describe('feature-service', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should fetch logo for given tenant', async () => {
mockGetLogo.mockResolvedValue(logoData);
const result = await getLogoForTenant(tenantId);
expect(mockGetLogo).toHaveBeenCalledWith(tenantId);
expect(result).toEqual(expectedLogo);
});
});
Key Patterns
- Always
jest.clearAllMocks()inbeforeEach— prevents cross-test contamination jest.MockedFunction<typeof fn>— type-safe mock setup- Module mocks at top level —
jest.mock()calls hoisted automatically - Test one behavior per
it()— clear arrange/act/assert
Playwright E2E
Configuration
Location: playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
import { getEnvironment } from './tests/config/environments';
const env = getEnvironment(); // reads TEST_ENV env var, defaults to 'dev'
export default defineConfig({
testDir: './tests',
fullyParallel: true,
workers: process.env.CI ? 2 : 3,
maxFailures: 1,
use: {
baseURL: env.baseUrl,
screenshot: 'only-on-failure',
video: 'retain-on-failure',
navigationTimeout: 60000,
actionTimeout: 30000,
},
projects: [
{ name: 'setup-auth', testMatch: '**/setup/authen.setup.ts' },
{ name: 'setup-cleanup', testMatch: '**/setup/cleanup.setup.ts', dependencies: ['setup-auth'] },
{
name: 'feature-navigation',
use: { ...devices['Desktop Chrome'], storageState: 'playwright/.auth/user.json' },
dependencies: ['setup-auth', 'setup-cleanup'],
testMatch: '**/feature-a/feature-navigation.spec.ts',
},
],
});
Environment Config
// tests/config/environments.ts
export const environments: Record<string, TestEnvironment> = {
local: { baseUrl: 'http://localhost:3000', ... },
dev: { baseUrl: 'https://app-dev.example.com', ... },
staging: { baseUrl: 'https://app-staging.example.com', ... },
test: { baseUrl: 'https://app-test.example.com', ... },
};
PageHelper
// tests/helpers/navigation.helpers.ts
export class PageHelper {
constructor(private page: Page) {}
async goToFeatureTab() {
await this.triggerSelectorAndWaitForNavigation('div[id="feature-a"]', /.*feature-a.*/);
await expect(this.page).toHaveURL(/.*feature-a.*/);
return this;
}
triggerSelectorAndWaitForNavigation = async (selector: string, urlPattern: RegExp) => {
const element = await this.page.waitForSelector(selector, { timeout: 5000 });
await Promise.all([element.click(), this.page.waitForURL(urlPattern, { timeout: 10000 })]);
};
}
E2E Test Pattern
test.describe.serial('Feature Tab - Sequential Tests', () => {
let pageHelper: PageHelper;
test.beforeEach(async ({ page }) => {
test.setTimeout(120000); // 120 seconds per test
pageHelper = new PageHelper(page);
await page.goto(`${env.baseUrl}/en`);
await page.waitForLoadState('domcontentloaded');
await pageHelper.goToFeatureTab();
});
test('01 - Create Item', async ({ page }) => {
await createItem({ page, itemName });
});
});
API Call Helpers
// tests/helpers/api-call.helpers.ts — module-level cached auth
export const cleanupTestData = async () => {
const response = await fetch(`${env.baseUrl}/api/internal/e2e-test/cleanup?tenantId=${tenantId}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${token}`, 'x-api-key': E2E_API_KEY },
});
};
Test Commands
# Unit tests
npm test # All tests
npm test -- --testFile=path/to/test # Single file
npm test -- --coverage # With coverage
# E2E tests
TEST_ENV=dev npx playwright test # Run against dev
npx playwright test --ui # Interactive UI mode
Rules
- Mirror app structure in
tests/directory - Use
jest.MockedFunction<typeof fn>for type-safe mocks - Always
jest.clearAllMocks()inbeforeEach - Use
test.describe.serialfor E2E tests with order dependencies - Set
test.setTimeout(120000)for E2E tests — default is too short - Use page helpers for navigation in E2E
- Use
storageStatefor authenticated E2E tests (avoid re-login per test)
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?