API testing template with Playwright, TypeScript, GraphQL, and OAuth 2.0 (Authorization Code + PKCE).
- Playwright Test Runner - Powerful API testing framework
- TypeScript - Full type safety with strict mode enabled
- GraphQL Support - Functional GraphQL client using graphql-request
- OAuth 2.0 + PKCE - Secure authentication flow (Azure B2C compatible)
- Zod Validation - Environment variable validation
- Cockatiel Retry Policy - Professional retry logic with exponential backoff for 401 errors
- Mutation Helpers - Type-safe parametrized mutations
- ESLint + Prettier - Code quality and formatting
- Functional Approach - Pure functions over classes following coding guide
- ClientError Types - Proper error handling with graphql-request types
- Node.js >=25.0.0
- npm, pnpm, bun
- Clone the repository:
git clone <repository-url>
cd playwright-api- Install dependencies:
npm install- Install Playwright:
npx playwright install- Copy the example environment file:
cp .env.example .env- Fill in your credentials in
.env:
# GraphQL API Endpoint
GRAPHQL_ENDPOINT=https://someapp.com/graphql
# OAuth 2.0 Configuration (Azure B2C)
AUTH_URL=https://someapp.b2clogin.com/.../oauth2/v2.0/authorize
TOKEN_URL=https://someapp.b2clogin.com/.../oauth2/v2.0/token
CLIENT_ID=your-client-id-uuid
REDIRECT_URI=com.someapp://auth/
SCOPE=https://.../.../someapp.Api
# Optional: Pre-configured Access Token (for testing without OAuth)
# ACCESS_TOKEN=your_access_token_hereplaywright-api/
├── src/
│ ├── config/
│ │ └── env.config.ts # Environment validation (Zod)
│ ├── types/
│ │ ├── auth.types.ts # OAuth 2.0 types
│ │ ├── graphql.types.ts # GraphQL types
│ │ └── api.types.ts # Common API types
│ ├── helpers/
│ │ ├── auth.helper.ts # OAuth 2.0 + PKCE (functional)
│ │ ├── graphql.helper.ts # GraphQL functions (query, mutation)
│ │ ├── mutation.helper.ts # Parametrized mutation builder
│ │ └── crypto.helper.ts # PKCE utilities
│ ├── fixtures/
│ │ └── api.fixture.ts # Playwright test fixtures
│ └── tests/
│ └── example.spec.ts # Example test file
├── .env.example # Environment template
├── .gitignore
├── .prettierrc # Prettier config
├── .eslintrc.json # ESLint config
├── playwright.config.ts # Playwright config
├── tsconfig.json # TypeScript config
├── package.json
└── README.md
npm testnpm run test:debugnpm run test:reportnpx playwright test src/tests/example.spec.tsnpx playwright test --headedThis template implements OAuth 2.0 Authorization Code flow with PKCE (Proof Key for Code Exchange) for enhanced security.
- Generate PKCE parameters -
code_verifierandcode_challenge - Build authorization URL - Redirect user to OAuth provider
- Exchange code for token - Trade authorization code for access token
- Automatic token refresh - Refresh expired tokens automatically
For testing without full OAuth flow, set ACCESS_TOKEN in .env:
ACCESS_TOKEN=your_bearer_token_hereImplement complete OAuth flow using provided helpers:
import { generatePKCEParams, getAuthorizationUrl, exchangeCodeForToken } from '@helpers/auth.helper'
const pkceParams = generatePKCEParams()
const authUrl = getAuthorizationUrl(pkceParams)
console.log('Visit:', authUrl)
const token = await exchangeCodeForToken(authorizationCode, pkceParams.codeVerifier)import { test, expect } from '@fixtures/api.fixture'
test.describe('User API Tests', () => {
test('should fetch user data', async ({ graphql }) => {
const query = `
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`
const variables = { id: '123' }
const response = await graphql.query(query, variables)
expect(response.user).toBeDefined()
expect(response.user.id).toBe('123')
})
})The template provides these fixtures:
authToken- Access token stringgraphql- GraphQL functions (query, mutation, rawRequest)
test('should use auth token', async ({ authToken }) => {
expect(authToken).toBeDefined()
})
test('should query graphql', async ({ graphql }) => {
const data = await graphql.query('{ __typename }')
expect(data).toBeDefined()
})test('should create user', async ({ graphql }) => {
const mutation = `
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
}
}
`
const variables = {
input: {
name: 'John Doe',
email: 'john@example.com',
},
}
const response = await graphql.mutation(mutation, variables)
expect(response.createUser.id).toBeDefined()
})import { createMutation } from '@helpers/mutation.helper'
interface CreateUserInput {
input: {
name: string
email: string
}
}
interface CreateUserResponse {
createUser: {
id: string
name: string
}
}
const createUser = createMutation<CreateUserInput, CreateUserResponse>(`
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
}
}
`)
test('should create user with helper', async () => {
const response = await createUser({
input: {
name: 'John Doe',
email: 'john@example.com',
},
})
expect(response.createUser.id).toBeDefined()
})npm run type-checknpm run lintnpm run formatnpm run format:checkFor production use, consider using graphql-codegen to auto-generate types:
- Install:
npm install -D @graphql-codegen/cli @graphql-codegen/typescript- Create
codegen.yml:
schema: ${GRAPHQL_ENDPOINT}
documents: 'src/**/*.graphql'
generates:
src/types/generated/graphql.ts:
plugins:
- typescript
- typescript-operations- Generate types:
npx graphql-codegen- Never commit
.envfile (already in.gitignore) - Use PKCE for OAuth flows (implemented)
- Rotate access tokens regularly
- Store sensitive data securely
- Use HTTPS endpoints only
- Validate environment variables (Zod)
- Proper error handling with typed errors from graphql-request
If you see Zod validation errors on startup:
Environment validation failed:
- GRAPHQL_ENDPOINT: Invalid url
Check your .env file and ensure all required variables are set correctly.
If authentication fails:
- Verify
ACCESS_TOKENin.envis valid - Check token expiration
- Ensure OAuth credentials are correct
- Verify network/VPN access to auth endpoints
If imports like @helpers/* don't resolve:
- Restart your IDE/editor
- Run
npm run type-checkto verify - Check
tsconfig.jsonpaths configuration
- Playwright Documentation
- GraphQL Documentation
- OAuth 2.0 PKCE
- TypeScript Handbook
- Zod Documentation
- Cockatiel Documentation - Resilience and retry policies
- Project Coding Guide - TypeScript best practices for this project
MIT
Happy Testing!