xiaohongshu
xiaohongshu
api-testing
REST and GraphQL API testing with Playwright. Use when testing APIs, mocking endpoints, validating responses, or integrating API tests with E2E flows.
Full skill instructions
Comprehensive API testing for REST and GraphQL endpoints using Playwright's built-in API testing capabilities.
import { test, expect } from '@playwright/test';
test('GET /api/users returns users', async ({ request }) => {
const response = await request.get('/api/users');
expect(response.ok()).toBeTruthy();
expect(response.status()).toBe(200);
const users = await response.json();
expect(users).toHaveLength(10);
expect(users[0]).toHaveProperty('email');
});
# Playwright includes API testing - no extra packages needed
npm install -D @playwright/test
playwright.config.ts:
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests',
use: {
baseURL: 'http://localhost:3000',
extraHTTPHeaders: {
'Accept': 'application/json',
},
},
projects: [
{
name: 'api',
testMatch: /.*\.api\.spec\.ts/,
},
{
name: 'e2e',
testMatch: /.*\.e2e\.spec\.ts/,
use: { browserName: 'chromium' },
},
],
});
test('fetch user by ID', async ({ request }) => {
const response = await request.get('/api/users/123');
expect(response.ok()).toBeTruthy();
const user = await response.json();
expect(user.id).toBe(123);
expect(user.email).toMatch(/@/);
});
test('create new user', async ({ request }) => {
const response = await request.post('/api/users', {
data: {
name: 'John Doe',
email: '[email protected]',
},
});
expect(response.status()).toBe(201);
const user = await response.json();
expect(user.id).toBeDefined();
expect(user.name).toBe('John Doe');
});
test('update user', async ({ request }) => {
const response = await request.put('/api/users/123', {
data: {
name: 'Jane Doe',
},
});
expect(response.ok()).toBeTruthy();
const user = await response.json();
expect(user.name).toBe('Jane Doe');
});
test('delete user', async ({ request }) => {
const response = await request.delete('/api/users/123');
expect(response.status()).toBe(204);
// Verify deletion
const getResponse = await request.get('/api/users/123');
expect(getResponse.status()).toBe(404);
});
test.describe('authenticated requests', () => {
let token: string;
test.beforeAll(async ({ request }) => {
const response = await request.post('/api/auth/login', {
data: {
email: '[email protected]',
password: 'password123',
},
});
const data = await response.json();
token = data.token;
});
test('access protected endpoint', async ({ request }) => {
const response = await request.get('/api/protected', {
headers: {
'Authorization': `Bearer ${token}`,
},
});
expect(response.ok()).toBeTruthy();
});
});
test('login and access dashboard', async ({ request, context }) => {
// Login (sets cookie automatically)
await request.post('/api/auth/login', {
data: { email: '[email protected]', password: 'pass' },
});
// Cookie is automatically included in subsequent requests
const response = await request.get('/api/dashboard');
expect(response.ok()).toBeTruthy();
});
test('GraphQL query users', async ({ request }) => {
const response = await request.post('/graphql', {
data: {
query: `
query GetUsers {
users {
id
name
email
}
}
`,
},
});
const { data, errors } = await response.json();
expect(errors).toBeUndefined();
expect(data.users).toHaveLength(10);
});
test('GraphQL create user', async ({ request }) => {
const response = await request.post('/graphql', {
data: {
query: `
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
email
}
}
`,
variables: {
input: {
name: 'John Doe',
email: '[email protected]',
},
},
},
});
const { data, errors } = await response.json();
expect(errors).toBeUndefined();
expect(data.createUser.id).toBeDefined();
});
test('GraphQL with auth', async ({ request }) => {
const response = await request.post('/graphql', {
headers: {
'Authorization': `Bearer ${token}`,
},
data: {
query: `
query Me {
me {
id
email
role
}
}
`,
},
});
const { data } = await response.json();
expect(data.me.role).toBe('admin');
});
test('display mocked products', async ({ page }) => {
// Mock the API
await page.route('**/api/products', route => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([
{ id: 1, name: 'Mock Product', price: 99.99 },
]),
});
});
await page.goto('/products');
await expect(page.locator('.product')).toHaveCount(1);
await expect(page.locator('.product-name')).toHaveText('Mock Product');
});
test('handle API error gracefully', async ({ page }) => {
await page.route('**/api/products', route => {
route.fulfill({
status: 500,
body: JSON.stringify({ error: 'Server error' }),
});
});
await page.goto('/products');
await expect(page.locator('.error-message')).toBeVisible();
});
test('show loading state', async ({ page }) => {
await page.route('**/api/products', async route => {
await new Promise(r => setTimeout(r, 2000));
route.fulfill({
status: 200,
body: JSON.stringify([]),
});
});
await page.goto('/products');
await expect(page.locator('.loading-spinner')).toBeVisible();
});
import Ajv from 'ajv';
const ajv = new Ajv();
const userSchema = {
type: 'object',
properties: {
id: { type: 'number' },
name: { type: 'string' },
email: { type: 'string', format: 'email' },
},
required: ['id', 'name', 'email'],
};
test('validate response schema', async ({ request }) => {
const response = await request.get('/api/users/1');
const user = await response.json();
const validate = ajv.compile(userSchema);
expect(validate(user)).toBeTruthy();
});
test('check response headers', async ({ request }) => {
const response = await request.get('/api/users');
expect(response.headers()['content-type']).toContain('application/json');
expect(response.headers()['x-rate-limit-remaining']).toBeDefined();
});
import path from 'path';
test('upload file', async ({ request }) => {
const response = await request.post('/api/upload', {
multipart: {
file: {
name: 'test.pdf',
mimeType: 'application/pdf',
buffer: Buffer.from('PDF content'),
},
description: 'Test document',
},
});
expect(response.ok()).toBeTruthy();
const result = await response.json();
expect(result.filename).toBe('test.pdf');
});
afterEach or afterAll hooksreferences/graphql-testing.md - Advanced GraphQL patternsreferences/schema-validation.md - JSON Schema with Ajvxiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience