From playwright-api
Create authenticated APIRequestContext fixtures with base URL config, shared headers, token management, and teardown cleanup. Produces a typed api-client.ts fixture barrel used by all API spec files.
How this skill is triggered — by the user, by Claude, or both
Slash command
/playwright-api:api-fixture-generationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill generates the `tests/api/fixtures/api-client.ts` barrel that all API spec files import. The fixture extends Playwright's base `test` with a typed `apiClient` fixture that provides an authenticated `APIRequestContext`, manages tokens, and cleans up created resources in teardown.
This skill generates the tests/api/fixtures/api-client.ts barrel that all API spec files import. The fixture extends Playwright's base test with a typed apiClient fixture that provides an authenticated APIRequestContext, manages tokens, and cleans up created resources in teardown.
Produces tests/api/fixtures/api-client.ts (path controlled by apiTestDir in .playwright-agent.json). The file exports an extended test object and expect.
test.extendimport { test as base, expect, type APIRequestContext } from '@playwright/test';
type ApiFixtures = {
apiClient: APIRequestContext;
};
export const test = base.extend<ApiFixtures>({
apiClient: async ({ playwright }, use) => {
// Create a new APIRequestContext with base URL and auth headers
const context = await playwright.request.newContext({
baseURL: process.env.API_BASE_URL ?? 'http://localhost:3000/api',
extraHTTPHeaders: {
Authorization: `Bearer ${process.env.API_AUTH_TOKEN ?? ''}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
// Provide context to the test
await use(context);
// Teardown — dispose the context and flush any pending requests
await context.dispose();
},
});
export { expect };
When the API uses a short-lived token that must be fetched before each test session, generate a token-fetching helper and call it during fixture setup:
import { test as base, expect, type APIRequestContext } from '@playwright/test';
async function fetchAuthToken(): Promise<string> {
const res = await fetch(`${process.env.API_BASE_URL}/auth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
clientId: process.env.API_CLIENT_ID,
clientSecret: process.env.API_CLIENT_SECRET,
}),
});
if (!res.ok) {
throw new Error(`Failed to fetch auth token: ${res.status}`);
}
const { access_token } = await res.json();
return access_token;
}
type ApiFixtures = {
apiClient: APIRequestContext;
};
export const test = base.extend<ApiFixtures>({
apiClient: async ({ playwright }, use) => {
const token = await fetchAuthToken();
const context = await playwright.request.newContext({
baseURL: process.env.API_BASE_URL ?? 'http://localhost:3000/api',
extraHTTPHeaders: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
await use(context);
await context.dispose();
},
});
export { expect };
When tests create resources that must be removed after the test, collect their IDs and delete them in teardown:
type ApiFixtures = {
apiClient: APIRequestContext;
createdUserIds: string[];
};
export const test = base.extend<ApiFixtures>({
// Shared array to accumulate IDs during a test
createdUserIds: [[], { scope: 'test' }],
apiClient: async ({ playwright, createdUserIds }, use) => {
const context = await playwright.request.newContext({
baseURL: process.env.API_BASE_URL ?? 'http://localhost:3000/api',
extraHTTPHeaders: {
Authorization: `Bearer ${process.env.API_AUTH_TOKEN ?? ''}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
await use(context);
// Cleanup — delete all resources created during this test
for (const id of createdUserIds) {
await context.delete(`/users/${id}`).catch(() => {
// Ignore 404s — resource may have been deleted by the test itself
});
}
await context.dispose();
},
});
export { expect };
Usage in a spec:
import { test, expect } from '../fixtures/api-client';
test('should create and clean up a user', async ({ apiClient, createdUserIds }) => {
const res = await apiClient.post('/users', {
data: { name: 'Temp User', email: '[email protected]' },
});
expect(res.status()).toBe(201);
const { id } = await res.json();
// Register for teardown cleanup
createdUserIds.push(id);
// ... rest of the test
});
When tests require different permission levels, generate a fixture per role:
type ApiFixtures = {
apiClient: APIRequestContext; // authenticated as standard user
adminApiClient: APIRequestContext; // authenticated as admin
};
export const test = base.extend<ApiFixtures>({
apiClient: async ({ playwright }, use) => {
const context = await playwright.request.newContext({
baseURL: process.env.API_BASE_URL ?? 'http://localhost:3000/api',
extraHTTPHeaders: {
Authorization: `Bearer ${process.env.API_USER_TOKEN ?? ''}`,
'Content-Type': 'application/json',
},
});
await use(context);
await context.dispose();
},
adminApiClient: async ({ playwright }, use) => {
const context = await playwright.request.newContext({
baseURL: process.env.API_BASE_URL ?? 'http://localhost:3000/api',
extraHTTPHeaders: {
Authorization: `Bearer ${process.env.API_ADMIN_TOKEN ?? ''}`,
'Content-Type': 'application/json',
},
});
await use(context);
await context.dispose();
},
});
export { expect };
Always read sensitive values from environment variables. Never hardcode credentials or base URLs:
| Variable | Purpose |
|---|---|
API_BASE_URL | Base URL for all API requests |
API_AUTH_TOKEN | Static bearer token for non-rotating auth |
API_CLIENT_ID | OAuth client ID for token exchange |
API_CLIENT_SECRET | OAuth client secret for token exchange |
API_USER_TOKEN | Token for standard-user role fixture |
API_ADMIN_TOKEN | Token for admin-role fixture |
Store defaults for local development in a .env.test file that is git-ignored.
npx claudepluginhub gagandeepp/software-agent-teams --plugin playwright-apiGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.