Node.js Test Tipps - REST API mit CORS

Im dritten Beitrag zu Node.js-Testtipps stelle ich meinen Ansatz zur Prüfung der REST-Schnittstelle vor. Wie gewohnt gibt es Hands-on-Codebeispiele und die Liste der notwendigen NPM-Pakete, damit du das in wenigen Minuten bei dir zum Laufen bringst. Legen wir mit dem heutigen Schwerpunkt auf CORS los.

3 Minuten
Hero image

Im Gegensatz zum In-Memory-Dateisystem- oder In-Memory-MongoDB-Testen, benötigen wir für die REST-Schnittstellen-Tests keine globalen Anpassungen an Vitest vorzunehmen. Wir können passend zur Controller-Datei direkt in der zugehörigen Controller-Testdatei arbeiten.

Beginnen wir damit, die Dev-Dependencies zu installieren:

npm install -D supertest

Ich gehe davon aus, dass du in deinem Code eine Express-App erstellst und für den Aufruf http.createServer(app) in einer Datei wie createApp.ts zurückgibst. Das benötigen wir, um einen Testagenten mit Supertest zu erstellen.

import supertest from 'supertest'
import createApp from '@/createApp'

const agent = supertest.agent(createApp())

Wie du siehst, ist das alles mit wenig Aufwand eingerichtet. Für die tägliche Nutzung habe ich ein paar Tipps mitgebracht, die dir vielleicht helfen.

Superagent REST-API-Helfer

CORS

Unter der Annahme, dass du deine Schnittstelle mit CORS-Headern ausstattest, hast du das in folgender Art eingerichtet:

app.use(
    cors({
      origin: '*', // reduce to your domain
      methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
      preflightContinue: false,
      optionsSuccessStatus: 204,
      exposedHeaders: ['x-correlation-id', 'etag'],
    }),
  ) // add CORS header for all requests

Für die Schnittstellentests gibt es einen Testhelfer, der das abtestet:

import supertest from 'supertest'

export default (agent: supertest.Agent, apiUrl: string) => {
  describe('OPTIONS', () => {
    it('should have headers set', async () => {
      // act
      const { status, headers } = await agent.options(apiUrl)

      // assert
      expect(status).toEqual(204)
      expect(headers['access-control-allow-origin']).toBe('*')
      expect(headers['access-control-allow-methods']).toBe('GET,HEAD,PUT,PATCH,POST,DELETE')
      expect(headers['access-control-expose-headers']).toBe('x-correlation-id,etag')
    })
  })
}

assertCorsHeaders.ts prüft für eine gegebene URL mithilfe des Agenten die Header

Der dazugehörige Test sieht wie folgt aus:

const baseUrl = '/users'

describe('UserController', () => {

  describe('GET all', () => {
    const apiUrl = baseUrl
    assertCorsHeaders(agent, baseUrl) // for the 
    // ...
  })

  describe('GET by id', () => {
    const apiUrl = baseUrl + '/entity-id'
    assertCorsHeaders(agent, apiUrl) // for get by id
    // ..
  })
})

Beispielhafte Struktur für das Testen des UserControllers

Ich mag die Verschachtelung der describe-Blöcke als Mittel zur Strukturierung meiner Tests. Über Tastenkürzel kann ich auf verschiedenen Ebenen Code-Folding aktivieren, sodass ich mittels Cmd+k+<level> eine klare Übersicht bekomme.

Hier ein Beispiel vom obigen UserController aus einem aktuellen Projekt

Im nächsten Post werde ich auf das Thema Authentifizierung in Verbindung mit Swagger und Tests eingehen. Das ist ein größerer Block – je nach Umfang teile ich die Inhalte auf mehrere Posts auf.

call to action background image

Abonniere meinen Newsletter

Erhalte einmal im Monat Nachrichten aus den Bereichen Softwareentwicklung und Kommunikation gespikt mit Buch- und Linkempfehlungen.