Saltar a contenido

SuperTest Cheatsheet

Instalación

Platform Command
npm (All Platforms) INLINE_CODE_20
Yarn (All Platforms) INLINE_CODE_21
With Jest INLINE_CODE_22
With Mocha INLINE_CODE_23
With TypeScript INLINE_CODE_24
Specific Version INLINE_CODE_25

Basic HTTP Métodos

Command Description
INLINE_CODE_26 Send GET request to endpoint
INLINE_CODE_27 Send POST request to endpoint
INLINE_CODE_28 Send PUT request to update resource
INLINE_CODE_29 Send PATCH request for partial update
INLINE_CODE_30 Send DELETE request to remove resource
INLINE_CODE_31 Send HEAD request (headers only)
INLINE_CODE_32 Send OPTIONS request for CORS preflight
INLINE_CODE_33 Send JSON data in request body
INLINE_CODE_34 Add query parameters to URL
INLINE_CODE_35 Set request header
INLINE_CODE_36 Assert HTTP status code
INLINE_CODE_37 Assert response header value
INLINE_CODE_38 Execute request with callback
INLINE_CODE_39 Execute request with Promise/async-await

Asserciones " Expectations

Command Description
INLINE_CODE_40 Expect exact status code
INLINE_CODE_41 Expect status and exact body match
INLINE_CODE_42 Expect exact header value
INLINE_CODE_43 Expect header matching regex
INLINE_CODE_44 Custom assertion function
INLINE_CODE_45 Expect status and body matching regex
INLINE_CODE_46 Expect redirect location header
INLINE_CODE_47 Expect exact JSON body match

Solicitar configuración

Command Description
INLINE_CODE_48 Set single request header
INLINE_CODE_49 Set multiple headers
INLINE_CODE_50 Set HTTP Basic Authentication
INLINE_CODE_51 Add form field (multipart)
INLINE_CODE_52 Attach file for upload
INLINE_CODE_53 Attach file from buffer
INLINE_CODE_54 Set request timeout in milliseconds
INLINE_CODE_55 Follow up to 5 redirects
INLINE_CODE_56 Set Content-Type header
INLINE_CODE_57 Set Accept header
INLINE_CODE_58 Send raw string body
INLINE_CODE_59 Send binary data

Advanced Usage

Command Description
INLINE_CODE_60 Create agent for persistent cookies
INLINE_CODE_61 Use agent for authenticated requests
INLINE_CODE_62 Test external API endpoints
INLINE_CODE_63 Custom response parser
INLINE_CODE_64 Buffer response body
INLINE_CODE_65 Set expected response type
INLINE_CODE_66 Retry failed requests 3 times
INLINE_CODE_67 Set custom CA certificate
INLINE_CODE_68 Set client certificate
INLINE_CODE_69 Set client private key
INLINE_CODE_70 Set PFX/PKCS12 certificate
INLINE_CODE_71 Disable TLS certificate validation

Testing Patterns

Pattern Description
INLINE_CODE_72 Store response for multiple assertions
INLINE_CODE_73 Assert on response body with test framework
INLINE_CODE_74 Assert on response headers
INLINE_CODE_75 Alternative status assertion
INLINE_CODE_76 Parallel request testing
INLINE_CODE_77 Sequential test requests

Configuración

Configuración de pruebas básicas

// test/setup.js
const request = require('supertest');
const app = require('../app');

module.exports = { request, app };

Configuración Jest

// jest.config.js
module.exports = {
  testEnvironment: 'node',
  testMatch: ['**/__tests__/**/*.test.js'],
  collectCoverageFrom: ['src/**/*.js'],
  coveragePathIgnorePatterns: ['/node_modules/']
};

Mocha Configuration

// test/mocha.opts
--require test/setup.js
--recursive
--timeout 5000
--exit

Package.json Scripts

{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "test:api": "jest --testPathPattern=api"
  }
}

Environment Variables

// config/test.js
module.exports = {
  port: process.env.TEST_PORT || 3001,
  database: process.env.TEST_DB || 'test_db',
  apiTimeout: process.env.API_TIMEOUT || 5000
};

Common Use Cases

Use Case 1: Testing REST API CRUD Operations

const request = require('supertest');
const app = require('../app');

describe('User API', () => {
  let userId;

  // Create
  test('POST /api/users - create user', async () => {
    const res = await request(app)
      .post('/api/users')
      .send({ name: 'John Doe', email: 'john@example.com' })
      .expect(201)
      .expect('Content-Type', /json/);

    userId = res.body.id;
    expect(res.body.name).toBe('John Doe');
  });

  // Read
  test('GET /api/users/:id - get user', async () => {
    await request(app)
      .get(`/api/users/${userId}`)
      .expect(200)
      .expect((res) => {
        expect(res.body.name).toBe('John Doe');
      });
  });

  // Update
  test('PUT /api/users/:id - update user', async () => {
    await request(app)
      .put(`/api/users/${userId}`)
      .send({ name: 'Jane Doe' })
      .expect(200);
  });

  // Delete
  test('DELETE /api/users/:id - delete user', async () => {
    await request(app)
      .delete(`/api/users/${userId}`)
      .expect(204);
  });
});

Use Case 2: Testing Authentication Flow

const request = require('supertest');
const app = require('../app');

describe('Authentication', () => {
  let authToken;

  test('POST /auth/register - register new user', async () => {
    await request(app)
      .post('/auth/register')
      .send({
        email: 'test@example.com',
        password: 'SecurePass123!',
        name: 'Test User'
      })
      .expect(201);
  });

  test('POST /auth/login - login user', async () => {
    const res = await request(app)
      .post('/auth/login')
      .send({
        email: 'test@example.com',
        password: 'SecurePass123!'
      })
      .expect(200)
      .expect('Content-Type', /json/);

    authToken = res.body.token;
    expect(authToken).toBeDefined();
  });

  test('GET /api/profile - access protected route', async () => {
    await request(app)
      .get('/api/profile')
      .set('Authorization', `Bearer ${authToken}`)
      .expect(200)
      .expect((res) => {
        expect(res.body.email).toBe('test@example.com');
      });
  });

  test('GET /api/profile - reject without token', async () => {
    await request(app)
      .get('/api/profile')
      .expect(401);
  });
});

Use Case 3: Testing File Upload

const request = require('supertest');
const app = require('../app');
const path = require('path');

describe('File Upload', () => {
  test('POST /api/upload - upload single file', async () => {
    const filePath = path.join(__dirname, 'fixtures', 'test.pdf');

    const res = await request(app)
      .post('/api/upload')
      .attach('document', filePath)
      .field('title', 'Test Document')
      .field('description', 'A test file upload')
      .expect(200)
      .expect('Content-Type', /json/);

    expect(res.body.filename).toMatch(/\.pdf$/);
    expect(res.body.size).toBeGreaterThan(0);
  });

  test('POST /api/upload - upload multiple files', async () => {
    await request(app)
      .post('/api/upload/multiple')
      .attach('files', 'test/fixtures/file1.pdf')
      .attach('files', 'test/fixtures/file2.pdf')
      .expect(200)
      .expect((res) => {
        expect(res.body.files).toHaveLength(2);
      });
  });
});

Use Case 4: Testing with Persistent Sessions

const request = require('supertest');
const app = require('../app');

describe('Session Management', () => {
  const agent = request.agent(app);

  test('Login and maintain session', async () => {
    // Login
    await agent
      .post('/auth/login')
      .send({ username: 'user', password: 'pass' })
      .expect(200);

    // Session persists - can access protected route
    await agent
      .get('/api/dashboard')
      .expect(200);

    // Session still valid for subsequent requests
    await agent
      .get('/api/profile')
      .expect(200);

    // Logout
    await agent
      .post('/auth/logout')
      .expect(200);

    // Session expired - access denied
    await agent
      .get('/api/dashboard')
      .expect(401);
  });
});

Use Case 5: Testing Error Handling

const request = require('supertest');
const app = require('../app');

describe('Error Handling', () => {
  test('404 - Resource not found', async () => {
    await request(app)
      .get('/api/users/99999')
      .expect(404)
      .expect((res) => {
        expect(res.body.error).toBe('User not found');
        expect(res.body.code).toBe('USER_NOT_FOUND');
      });
  });

  test('400 - Validation error', async () => {
    await request(app)
      .post('/api/users')
      .send({ name: '' }) // Invalid data
      .expect(400)
      .expect((res) => {
        expect(res.body.errors).toBeDefined();
        expect(res.body.errors.name).toContain('required');
      });
  });

  test('429 - Rate limit exceeded', async () => {
    // Make multiple requests to trigger rate limit
    const requests = Array(101).fill().map(() =>
      request(app).get('/api/users')
    );

    const responses = await Promise.all(requests);
    const rateLimited = responses.find(r => r.status === 429);

    expect(rateLimited).toBeDefined();
    expect(rateLimited.body.error).toMatch(/rate limit/i);
  });

  test('500 - Internal server error', async () => {
    await request(app)
      .get('/api/trigger-error')
      .expect(500)
      .expect((res) => {
        expect(res.body.error).toBe('Internal server error');
      });
  });
});

Buenas prácticas

  • Use async/await syntax: Más limpio y más legible que callbacks. El JavaScript moderno admite este patrón de forma nativa. javascript const res = await request(app).get('/api/users').expect(200);

  • Install as dev dependency: SuperTest es una herramienta de prueba y sólo debe estar en devDependencies, no dependencias de producción. bash npm install supertest --save-dev

  • No empiece el servidor manualmente: SuperTest maneja la unión del servidor automáticamente. Pase la aplicación Express directamente sin llamar app.listen()_. ```javascript // Good: Export app without listening module.exports = app;

// Bad: Don't do this in test files app.listen(3000); ```

  • Use request.agent() for session testing: Al probar rutas autenticadas o sesiones basadas en cookies, cree un agente que persista las cookies a través de las solicitudes. javascript const agent = request.agent(app); await agent.post('/login').send(credentials); await agent.get('/protected'); // Cookies persist

  • Cambiar las expectativas para pruebas limpias: Múltiples llamadas .expect() pueden ser encadenadas para afirmaciones integrales en una sola prueba. javascript await request(app) .get('/api/users') .expect(200) .expect('Content-Type', /json/) .expect((res) => expect(res.body).toHaveLength(10));

Respuestas extremas para afirmaciones complejas: Capturar el objeto de respuesta cuando usted necesita realizar múltiples afirmaciones en diferentes partes. javascript const res = await request(app).get('/api/users').expect(200); expect(res.body).toHaveLength(5); expect(res.headers['x-total-count']).toBe('100');

Test both success and failure cases: Siempre prueba escenarios de error, fallas de validación y casos de borde junto a caminos felices. javascript test('returns 404 for non-existent user', async () => { await request(app).get('/api/users/99999').expect(404); });

  • Usar nombres de prueba descriptivos: Escribir descripciones de pruebas que explican claramente qué comportamiento se está verificando. javascript test('POST /api/users returns 400 when email is missing', async () => { // Test implementation });

  • Clean up test data: Use beforeEach____afterEach ganchos para restablecer el estado de la base de datos y garantizar el aislamiento de la prueba. javascript afterEach(async () => { await User.deleteMany({}); });

  • Separar los plazos adecuados: Para puntos finales lentos o llamadas externas de API, configure los valores de timeout para evitar fallos falsos. javascript await request(app).get('/api/slow').timeout(10000).expect(200);

Troubleshooting

__TABLE_121_ No se puede probar API externas ← SuperTest funciona con URL externas: request('https://api.example.com').get('/endpoint'). Asegurar el acceso a la red y la disponibilidad de API. Silencio