Vai al contenuto

SuperTest Cheatsheet

Installazione

Tabella_115

Basic HTTP Metodi

Tabella_116_

Asserzioni e aspettative

Tabella_117_

Richiesta configurazione

Tabella_118

Uso avanzato

Tabella_119_

Testing Patterns

Tabella_120

Configurazione

Set di test di base

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

module.exports = { request, app };

Configurazione 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"
  }
}

Variabili ambientali

// 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');
      });
  });
});

Migliori Pratiche

  • Utilizza la sintassi asinc/await: Più pulita e più leggibile delle chiamate. Modern JavaScript supporta questo modello in modo nativo. Traduzione:

  • Install as dev dipendenza # SuperTest è uno strumento di prova e dovrebbe essere solo in devDependencies, non dipendenze di produzione.

    Traduzione:

  • ** Non avviare il server manualmente**: SuperTest gestisce automaticamente il binding del server. Passare l'applicazione Express direttamente senza chiamare app.listen().

  • ** Utilizzare request.agent() per i test di sessione**: Quando si verificano percorsi autenticati o sessioni basate sui cookie, creare un agente per persistere dei cookie attraverso le richieste. Traduzione:

  • **Cambiare le aspettative per i test più puliti ** Più chiamate .expect()_ possono essere incatenate per affermazioni complete in un unico test. Traduzione:

  • Rispondenze di vendita per affermazioni complesse: Cattura l'oggetto di risposta quando è necessario eseguire più affermazioni su parti diverse. Traduzione:

  • **I casi di successo e di fallimento ** Testare sempre scenari di errore, guasti di validazione e casi di bordo accanto a percorsi felici. Traduzione:

  • Utilizzare i nomi dei test descrittivi: Scrivere descrizioni dei test che spiegano chiaramente che comportamento viene verificato. Traduzione:

  • Clean up test data*: Utilizzare beforeEach/_INLINE_CODE_82__ per ripristinare lo stato del database e garantire l'isolamento del test. Traduzione:

  • Set timeouts appropriati**: Per gli endpoint lenti o le chiamate API esterne, configurare i valori di timeout per evitare errori falsi. Traduzione:

Risoluzione dei problemi

TABLE_121_| Non è possibile testare le API esterne | SuperTest funziona con URL esterni: request('https://api.example.com').get('/endpoint'). Assicurare l'accesso alla rete e la disponibilità API. #