When to Use
Use this skill when:
- Writing e2e tests for REST API endpoints
- Testing GraphQL mutations and queries via HTTP
- Testing authentication flows (JWT, OAuth, Basic Auth)
- Testing file upload endpoints
- Testing HTTP error responses and status codes
Core Supertest API
Basic Request Structure
import * as request from 'supertest';
// Basic GET request
request(app.getHttpServer())
.get('/endpoint')
.expect(200);
// POST with body
request(app.getHttpServer())
.post('/endpoint')
.send({ data: 'value' })
.expect(201);
Header Manipulation
// Set request headers
.set('Authorization', 'Bearer token')
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
// Assert response headers
.expect('Content-Type', /json/)
Response Body Assertions
// Custom assertions
.expect((res) => {
expect(res.body).toHaveProperty('id');
expect(res.body.name).toBe('Test');
})
Detailed References
- REST CRUD & Pagination Testing — CRUD operations, pagination, filtering, sorting
- Authentication Testing — JWT, API Key, protected routes, token refresh
- GraphQL Testing — Mutations, queries, error handling
- Advanced Patterns — File upload, DB seeding, custom test DB, error responses
Best Practices
✅ DO
- Use async/await: Modern pattern, cleaner than callbacks
- Set headers explicitly: Always set
AcceptandContent-Type - Test error paths: Not just happy paths
- Verify status codes: Always assert expected HTTP status
- Assert response structure: Check all important fields
- Clean up resources: Use
afterAllto close app - Use fixtures: Store test files in
test/fixtures/ - Seed data properly: Use seeders for consistent data
- Test authentication: Both success and failure scenarios
- Use descriptive test names: "should create model when data is valid"
❌ DON'T
- Don't skip status assertions: Always use
.expect(statusCode) - Don't test implementation: Test API contracts, not internals
- Don't share state: Each test should be independent
- Don't hardcode IDs: Generate or capture from responses
- Don't ignore error messages: Assert error content, not just status
- Don't forget cleanup: Close app in
afterAll - Don't mix unit and e2e: Keep them separate
- Don't test generated endpoints: Focus on custom logic
- Don't use production DB: Use test database or in-memory
Quick Reference
| Task | Pattern |
|------|---------|
| Basic GET | request(server).get('/path').expect(200) |
| POST with body | .post('/path').send({ data }).expect(201) |
| Set auth header | .set('Authorization', 'Bearer token') |
| Upload file | .attach('file', filepath) |
| Assert response | .expect((res) => { expect(res.body)... }) |
| Test GraphQL | .post('/graphql').send({ query }) |
| Chain requests | Store response, use in next request |
| Test pagination | .query({ limit: 10, offset: 0 }) |
Common HTTP Status Codes
| Code | Meaning | When to Use | |------|---------|-------------| | 200 | OK | Successful GET, PUT, DELETE | | 201 | Created | Successful POST (resource created) | | 204 | No Content | Successful DELETE (no body) | | 400 | Bad Request | Validation errors | | 401 | Unauthorized | Missing or invalid auth | | 403 | Forbidden | Valid auth but no permission | | 404 | Not Found | Resource doesn't exist | | 409 | Conflict | Duplicate entry | | 422 | Unprocessable Entity | Semantic validation error | | 500 | Internal Server Error | Server exception |
Remember
- e2e tests test the full request/response cycle
- Use real database or in-memory for integration
- Supertest wraps your NestJS app HTTP server
- Test authentication flows completely (login → use token → logout)
- Verify both success and failure scenarios
- Keep tests fast: Optimize database operations
- Run e2e separately:
npm run test:e2e
Scan to join WeChat group