AgentStack
SKILL verified Apache-2.0 Self-run

Playwright Test

skill-nexadevapp-nexa-claude-skills-marketplace-playwright-test · by nexadevapp

>

No reviews yet
0 installs
16 views
0.0% view→install

Install

$ agentstack add skill-nexadevapp-nexa-claude-skills-marketplace-playwright-test

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Playwright Test? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Playwright Test

Instructions

Create Playwright end-to-end tests for Next.js pages based on the use case $ARGUMENTS. Playwright tests run in a real browser against the running application with a real database via Testcontainers.

End-to-end means end-to-end. Each test walks the complete user journey from entry point to final outcome — exactly as a real user would. Tests navigate by clicking links and buttons, not by jumping to internal URLs. If a real user must click three screens to reach a form, the test clicks through those same three screens.

Inputs

| Input | Location | Required | |-------|----------|----------| | Use case specification | docs/use_cases/UC-XXX.md | Yes | | Frontend design | docs/designs/UC-XXX-design.html | Yes |

The use case specification defines what the system does (scenarios, alternative flows, business rules). The frontend design defines how it looks and behaves (screens, components, states, user actions, navigation flow). Together they determine the test scenarios and assertions:

  • Test scenarios derive from the use case Main Success Scenario and Alternative Flows
  • Page structure and selectors derive from the frontend design's Components and Layout sections
  • Assertions derive from the frontend design's States (default, loading, empty, error, success) and Data Displayed sections
  • User interactions derive from the frontend design's User Actions (triggers, results)
  • Navigation expectations derive from the frontend design's Navigation Flow and Screen Map

If docs/designs/$ARGUMENTS-design.html does not exist, stop and tell the user to run /design-screens $ARGUMENTS first.

Test Philosophy: Journeys, Not Fragments

The purpose of E2E tests is to verify that the complete user journey works end-to-end. Each test represents one path through the use case — either the Main Success Scenario or an Alternative Flow.

How many tests per use case:

  • 1 test for the Main Success Scenario (the happy path, all steps start to finish)
  • 1 test per Alternative Flow that diverges meaningfully from the MSS
  • Business rules are verified inline within the journey they belong to, not as separate tests

A typical use case produces 3–8 tests total, not dozens.

What makes it E2E:

  • The test starts at the application's entry point (e.g., landing page, login screen)
  • Every navigation happens through UI interactions (clicks, form submissions) — never page.goto() to internal pages
  • The test verifies intermediate states along the way, not just the final outcome
  • The test verifies Postconditions:
  • For success flows: data is visible and correctly stored in the system.
  • For failure flows: the system state remains unchanged (e.g., no partial records created, original values preserved). Use API calls in afterEach or inline to verify deep system state if UI-only verification is insufficient.
  • The test ends with a verifiable outcome (data visible, confirmation shown, redirect happened)

page.goto() is only used ONCE per test — to open the application entry point (e.g., page.goto('/') or page.goto('/login')). All subsequent navigation must happen through the UI.

Traceability Convention

E2E tests use the helper at e2e/helpers/traced.ts to link each test to its use case, change requests, and bug fixes. Use Cases are grouped with raw test.describe(...) (not a custom wrapper) so IDE plugins (WebStorm/IntelliJ, VSCode Playwright) can walk into the block and show gutter run icons for each test inside.

The helper exports three functions:

  • uc(id) — returns the { tag } options object for test.describe().

Validates the UC doc exists.

  • meta(uc, { scenario, verifies?, fixes? }) — returns Playwright's

{ tag, annotation } second-arg object for a test inside the describe. Validates referenced CR/BUG docs exist.

  • bug(id) — same shape, for a pure bug regression test that has no clean

UC home. Validates the BUG doc exists.

Anchor each UC group with test.describe(...) and uc(...):

import { test, expect } from '@playwright/test';
import { uc, meta } from './helpers/traced';

test.describe('UC-XXX: [Use Case Name]', uc('UC-XXX'), () => {
  test('[end-to-end journey description]',
    meta('UC-XXX', {
      scenario: 'MSS',
      verifies: ['CR-NNN'], // optional: change requests this test asserts the delta of
      fixes: ['BUG-NNN'],   // optional: bugs this test guards against regressing
    }),
    async ({ page }) => {
      // ... test body
    });

  test('[alternative flow description]',
    meta('UC-XXX', { scenario: 'AF-1' }),
    async ({ page }) => {
      // ... test body
    });
});

Multiple UCs per file (when journeys share a page or flow): one top-level test.describe(...) block per UC.

Pure bug regression tests (no clean UC home) — file bug-NNN-*.spec.ts:

import { test, expect } from '@playwright/test';
import { bug } from './helpers/traced';

test('[regression description]', bug('BUG-NNN'), async ({ page }) => {
  // ... test body
});

Scenario types (the required scenario field on meta('UC-NNN', {...})):

  • 'MSS' — Main Success Scenario (one per UC)
  • 'AF-N' — Alternative Flow N (e.g., 'AF-1', 'AF-2')
  • 'EX-N' — Exception path N

The helper validates that referenced UCs, CRs, and BUGs exist as files under docs/use_cases/, docs/change_requests/, and docs/bugs/ at registration time. A typo'd CR-002 fails before any browser starts.

Why raw test.describe() instead of a custom wrapper: JetBrains' Playwright plugin (and the VSCode equivalent) only walks test() and test.describe() calls — it does not enter callbacks of arbitrary helper functions. A useCase() wrapper that calls test.describe() internally works at runtime but hides the inner tests from the IDE's AST walker. Keeping test.describe(...) literally in source is what makes gutter run/debug icons appear for each test.

The UC id is repeated three times per describe (title, uc(), each meta()). This is intentional: a single source of truth would require either fragile module-level state or a wrapper the IDE can't see into.

Inline comments — when a single line/assertion exists because of a CR or BUG, leave a one-line marker comment so a code reader sees it without reading tags:

// CR-003: month/year picker
await page.locator('input[type="month"]').first().fill('2025-06');

// Verifies BR-001: [Rule Name]
await expect(page.getByText('Error')).toBeVisible();

// Verifies Success Postcondition: [Postcondition Name]
await expect(page.locator('table')).toContainText(['New Item']);

DO NOT

  • Navigate with page.goto() to internal pages — only use page.goto() once per test to open the entry point. All other navigation must happen through clicking links, buttons, and submitting forms. This is the most important rule: if you bypass navigation, you are not testing E2E
  • Write one test per step or per screen — each test must cover the full journey. A test that only checks "form displays correctly" is not an E2E test
  • Create separate tests for business rules — verify business rules inline within the journey where they apply
  • Run tests on multiple browsers — use Chromium only. The playwright.config.ts must have exactly one project
  • Access the database directly in tests — use the test API endpoints (/api/e2e/users) instead
  • Use waitForLoadState('networkidle') — it waits for zero network activity for 500ms, but Next.js dev-server HMR websockets, analytics pings, and prefetch requests can delay or prevent it from settling, causing flaky timeouts in CI. Instead, wait for the specific UI element that signals the page is ready (a heading, a table row, a form field)
  • Skip waiting for page loads or network requests to complete
  • Use hard-coded delays (page.waitForTimeout) instead of proper waits
  • Delete all data in cleanup (only remove data created during the test)
  • Hard-code database connection strings — DATABASE_URL is injected by global setup
  • Write tests that contradict the frontend design (e.g., asserting a table when the design specifies cards)
  • Skip, exclude, or filter out tests — never use --grep-invert, --grep, test.skip(), test.fixme(), or any other mechanism to avoid running tests. All tests must run and pass
  • Claim tests pass without verifying output — you must check the actual Playwright output for "X passed" and "0 failed" before declaring success
  • Sleep or wait between test retries — when tests fail, diagnose and fix the root cause immediately, then re-run. Never use sleep, setTimeout, or any delay between retry attempts. The fix-then-rerun cycle must be immediate
  • Ignore or work around database-dependent tests — Testcontainers provides the database; if Docker is not running, stop and tell the user instead of skipping DB tests
  • Write no-op or trivially-true tests — every test must contain meaningful assertions that would fail if the feature were broken (e.g., never assert expect(true).toBe(true) or assert only that a page loads without checking content)
  • Register a test or describe without the helper — every test(...) call in an E2E spec must be tagged via meta('UC-NNN', { scenario, ... }) (inside a test.describe) or bug('BUG-NNN') (pure regression, module scope). Every UC test.describe(...) must pass uc('UC-NNN') as its second arg. Raw test('title', async (...) => ...) or test.describe('title', () => {...}) with no helper metadata is a violation — it loses the traceability link, the HTML report annotation, and the registration-time doc validation

Nexa Rules Gate

Read and follow ${CLAUDE_PLUGIN_ROOT}/shared/readiness/NEXA_RULES_GATE.md.

Sprint Branch Gate

Read and follow ${CLAUDE_PLUGIN_ROOT}/shared/readiness/SPRINT_BRANCH_GATE.md.

Test User Provisioning

Every E2E test requires an authenticated user. User provisioning operates at two levels:

Suite-Level User (default)

Each test file provisions one shared user for all tests in the file. This user is a standard, fully-valid user suitable for happy-path scenarios.

Lifecycle (managed via test.beforeAll / test.afterAll):

  1. Before all tests: Create a user directly in the database via the test API endpoint:
  • Email: e2e-{random8chars}@example.com
  • Password: bcrypt-hashed (plaintext stored in a variable for login)
  • account_type: as needed by the use case (default to the most common type)
  • status: "ACTIVE"
  • email_confirmed: true
  • All consent flags: true
  • auth_provider: "EMAIL"
  • created_at / updated_at: current timestamp
  1. After each test: Clear cookies and storage to prevent session leakage between tests.
  2. After all tests: Delete the user and all related records via the test API endpoint.

Per-Test User Override

Individual tests that need a user with different characteristics (e.g., inactive status, unconfirmed email, a different account type) provision their own user, overriding the suite-level user.

Lifecycle (managed via test.beforeEach / test.afterEach or inline):

  1. Before the test: Create a custom user directly in the database via the test API endpoint:
  • Email: e2e-{random8chars}@example.com
  • Password: bcrypt-hashed (plaintext stored in a variable for login)
  • account_type: as needed by the specific test scenario
  • status: as needed by the test scenario (e.g., "SUSPENDED", "PENDING")
  • email_confirmed: as needed (e.g., false for unconfirmed-email flows)
  • All consent flags: true
  • auth_provider: "EMAIL"
  • created_at / updated_at: current timestamp
  1. Start of test: Log in as this custom user via the login page UI.
  2. After the test: Delete this custom user and all related records via the test API endpoint (use finally blocks to ensure cleanup runs even on failure). Cookies are cleared by the suite-level afterEach.

Test API Endpoint

The application must expose a test-only API endpoint for user provisioning and cleanup. This endpoint is only available when NODE_ENV=test:

  • POST /api/e2e/users — Creates a user in the database. Accepts the user fields above. Returns the created user with id.
  • DELETE /api/e2e/users/:id — Deletes the user and all related records (cascade).

If this endpoint does not exist in the project, create it before writing tests. Use the template at [templates/e2e-users-api.ts](templates/e2e-users-api.ts).

Test User Helper

Use the helper at [templates/test-user.ts](templates/test-user.ts) to provision and clean up users. If e2e/helpers/test-user.ts does not exist, create it from the template.

Other Test Data

| Approach | Location | Purpose | |-------------------|------------------------------|----------------------------------| | Prisma seed | prisma/seed.ts | Baseline reference data (non-user)| | API calls | Within test setup | Test-specific entity data | | Manual cleanup | afterEach hooks | Remove data created during test |

Test Data Conventions

  • Use only example.com for test emails and accounts (e.g., user@example.com, admin@example.com). This is an IANA-reserved domain that will never route real mail.

Testcontainers Global Setup

Before writing tests, ensure the project has a global setup file that starts a PostgreSQL Testcontainer, runs Prisma migrations, and seeds the database. The dev server is handled separately by Playwright's webServer option.

If e2e/global-setup.ts does not exist, create it using [templates/global-setup.ts](templates/global-setup.ts).

.env.e2e — Single Source of Truth

All E2E test environment variables live in a .env.e2e file at the project root. The global setup loads it via dotenv, and the webServer command sources it before starting the dev server. This eliminates dynamic env file generation and scattered env: blocks.

NODE_ENV=test
DATABASE_URL=postgresql://test:test@localhost:5432/testdb
DIRECT_URL=postgresql://test:test@localhost:5432/testdb
NEXT_PUBLIC_APP_URL=http://localhost:3000
AUTH_SECRET=test-secret-for-vitest-at-least-32-characters-long
AUTH_URL=http://localhost:3000
E2E_TEST=true

Add project-specific env vars as needed. Commit this file (add !.env.e2e to .gitignore if .env* is ignored).

Playwright Configuration

Single browser only — use Chromium. Do NOT add Firefox or WebKit projects. Cross-browser testing is not the purpose of E2E tests; verifying user journeys is.

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './e2e',
  globalSetup: './e2e/global-setup.ts',
  globalTeardown: './e2e/global-teardown.ts',
  fullyParallel: false,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 3 : 6,
  reporter: 'html',
  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
  },
  webServer: {
    // .env.e2e is the single source of truth for E2E test env vars.
    // `set -a` exports all sourced vars into the process environment.
    command: 'bash -c \'set -a; source .env.e2e; set +a; exec npx next dev\'',
    url: 'http://localhost:3000',
    reuseExistingServer: false,
    timeout: 60_000,
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    // Do NOT add firefox or webkit — single browser only for E2E
  ],
});

Templates

  • Global setup: [templates/global-setup.ts](templates/global-setup.ts)
  • Global teardown: [templates/global-teardown.ts](templates/global-teardown.ts)
  • Test user helper: [templates/test-user.ts](templates/test-user.ts)
  • E2E users API endpoint: [templates/e2e-users-a

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.