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
Accept and Content-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
afterAll to 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
1---2name: supertest-nestjs3description: Supertest patterns and best practices for NestJS e2e API testing. Trigger: When writing e2e tests, testing HTTP endpoints, or testing authentication flows in NestJS.4license: MIT5---6
7## When to Use
8
9Use this skill when:
10- Writing e2e tests for REST API endpoints
11- Testing GraphQL mutations and queries via HTTP
12- Testing authentication flows (JWT, OAuth, Basic Auth)
13- Testing file upload endpoints
14- Testing HTTP error responses and status codes
15
16## Core Supertest API
17
18### Basic Request Structure
19
20```typescript
21import * as request from 'supertest';
22
23// Basic GET request
24request(app.getHttpServer())
25 .get('/endpoint')
26 .expect(200);
27
28// POST with body
29request(app.getHttpServer())
30 .post('/endpoint')
31 .send({ data: 'value' })
32 .expect(201);
33```
34
35### Header Manipulation
36
37```typescript
38// Set request headers
39.set('Authorization', 'Bearer token')
40.set('Content-Type', 'application/json')
41.set('Accept', 'application/json')
42
43// Assert response headers
44.expect('Content-Type', /json/)
45```
46
47### Response Body Assertions
48
49```typescript
50// Custom assertions
51.expect((res) => {
52 expect(res.body).toHaveProperty('id');
53 expect(res.body.name).toBe('Test');
54})
55```
56
57## Detailed References
58
59- [REST CRUD & Pagination Testing](rest-crud.md) — CRUD operations, pagination, filtering, sorting
60- [Authentication Testing](auth-testing.md) — JWT, API Key, protected routes, token refresh
61- [GraphQL Testing](graphql-testing.md) — Mutations, queries, error handling
62- [Advanced Patterns](advanced-patterns.md) — File upload, DB seeding, custom test DB, error responses
63
64## Best Practices
65
66### ✅ DO
67
681. **Use async/await**: Modern pattern, cleaner than callbacks
692. **Set headers explicitly**: Always set `Accept` and `Content-Type`
703. **Test error paths**: Not just happy paths
714. **Verify status codes**: Always assert expected HTTP status
725. **Assert response structure**: Check all important fields
736. **Clean up resources**: Use `afterAll` to close app
747. **Use fixtures**: Store test files in `test/fixtures/`
758. **Seed data properly**: Use seeders for consistent data
769. **Test authentication**: Both success and failure scenarios
7710. **Use descriptive test names**: "should create model when data is valid"
78
79### ❌ DON'T
80
811. **Don't skip status assertions**: Always use `.expect(statusCode)`
822. **Don't test implementation**: Test API contracts, not internals
833. **Don't share state**: Each test should be independent
844. **Don't hardcode IDs**: Generate or capture from responses
855. **Don't ignore error messages**: Assert error content, not just status
866. **Don't forget cleanup**: Close app in `afterAll`
877. **Don't mix unit and e2e**: Keep them separate
888. **Don't test generated endpoints**: Focus on custom logic
899. **Don't use production DB**: Use test database or in-memory
90
91## Quick Reference
92
93| Task | Pattern |
94|------|---------|
95| Basic GET | `request(server).get('/path').expect(200)` |
96| POST with body | `.post('/path').send({ data }).expect(201)` |
97| Set auth header | `.set('Authorization', 'Bearer token')` |
98| Upload file | `.attach('file', filepath)` |
99| Assert response | `.expect((res) => { expect(res.body)... })` |
100| Test GraphQL | `.post('/graphql').send({ query })` |
101| Chain requests | Store response, use in next request |
102| Test pagination | `.query({ limit: 10, offset: 0 })` |
103
104## Common HTTP Status Codes
105
106| Code | Meaning | When to Use |
107|------|---------|-------------|
108| 200 | OK | Successful GET, PUT, DELETE |
109| 201 | Created | Successful POST (resource created) |
110| 204 | No Content | Successful DELETE (no body) |
111| 400 | Bad Request | Validation errors |
112| 401 | Unauthorized | Missing or invalid auth |
113| 403 | Forbidden | Valid auth but no permission |
114| 404 | Not Found | Resource doesn't exist |
115| 409 | Conflict | Duplicate entry |
116| 422 | Unprocessable Entity | Semantic validation error |
117| 500 | Internal Server Error | Server exception |
118
119## Remember
120
121- **e2e tests** test the full request/response cycle
122- **Use real database** or in-memory for integration
123- **Supertest** wraps your NestJS app HTTP server
124- **Test authentication flows** completely (login → use token → logout)
125- **Verify both success and failure** scenarios
126- **Keep tests fast**: Optimize database operations
127- **Run e2e separately**: `npm run test:e2e`