Testing
The testing package provides comprehensive utilities and helpers for testing NestJS applications that use AWS Cognito authentication. It supports both real E2E testing with actual AWS services and mocked testing for faster development cycles.
Getting Started with Testing
To begin testing your NestJS Cognito authentication, you'll need to install the required packages:
pnpm add --save-dev @nestjs-cognito/testing # NestJS Cognito testing utilities
pnpm add --save-dev @nestjs/testing # NestJS testing utilities
pnpm add --save-dev jest # Test runner
pnpm add --save-dev @types/jest # TypeScript definitions
HTTP Testing with Pactum
Pactum is a HTTP testing toolkit that makes it easy to test NestJS Cognito authentication endpoints.
pnpm add --save-dev pactum # HTTP testing toolkit
Setting Up Pactum
import { handler, request, spec } from "pactum";
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
describe('Auth Tests', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleRef.createNestApplication();
await app.init();
// Configure Pactum to use the NestJS application
request.setBaseUrl(`http://localhost:${process.env.PORT || 3000}`);
});
afterAll(async () => {
await app.close();
});
});
Real E2E Testing
Real E2E testing allows you to validate your application against actual AWS Cognito services, ensuring production-ready authentication flows.
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { CognitoTestingModule } from '@nestjs-cognito/testing';
import { CognitoAuthModule } from '@nestjs-cognito/auth';
@Module({
imports: [
// Configure auth module with environment variables
CognitoAuthModule.registerAsync({
imports: [ConfigModule.forRoot()],
useFactory: (config: ConfigService) => ({
jwtVerifier: {
userPoolId: config.get('COGNITO_USER_POOL_ID'),
clientId: config.get('COGNITO_CLIENT_ID'),
tokenUse: 'id',
},
}),
inject: [ConfigService],
}),
// Configure testing module with AWS credentials
CognitoTestingModule.registerAsync({
imports: [ConfigModule.forRoot()],
useFactory: (config: ConfigService) => ({
identityProvider: {
region: config.get('COGNITO_REGION'),
},
}),
inject: [ConfigService],
}),
],
})
export class TestModule {}
Mock Testing
Mock testing is useful during development and CI/CD pipelines where real AWS Cognito services are not available or desired. Note that you must provide the mock configuration as the second argument to CognitoTestingModule.register()
and explicitly enable mock mode.
import { COGNITO_JWT_VERIFIER_INSTANCE_TOKEN } from '@nestjs-cognito/core';
import { CognitoTestingModule } from '@nestjs-cognito/testing';
import { Test } from "@nestjs/testing";
import { handler, request, spec } from "pactum";
describe('Auth Tests', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
imports: [
CognitoTestingModule.register({}, {
enabled: true, // Enable mock mode
user: {
username: 'test-user',
email: 'test@example.com',
groups: ['users'],
},
}),
AppModule,
],
})
.overrideProvider(COGNITO_JWT_VERIFIER_INSTANCE_TOKEN)
.useFactory({
factory: CognitoTestingModule.createJwtVerifierFactory
})
.compile();
app = moduleFixture.createNestApplication();
await app.init();
});
});
Testing Scenarios
Authentication Testing
// Test authentication using mock service
const response = await request(app.getHttpServer())
.post('/cognito-testing-login')
.send({
username: 'test-user',
password: 'any-password', // Password is not validated in mock mode
clientId: 'mock-client-id'
})
.expect(200);
// Test protected routes
await request(app.getHttpServer())
.get('/protected')
.set('Authorization', `Bearer ${response.body.AccessToken}`)
.expect(200)
.expect({
username: 'test-user',
email: 'test@example.com',
groups: ['users'],
});
Authorization Testing
// Test group-based authorization
describe('Authorization Tests', () => {
it('should allow access to authorized group members', async () => {
// Configure mock user with specific group
await request(app.getHttpServer())
.post('/config')
.send({
enabled: true,
user: {
username: 'admin-user',
email: 'admin@example.com',
groups: ['admin'],
},
})
.expect(200);
// Login and get token
const loginResponse = await request(app.getHttpServer())
.post('/cognito-testing-login')
.send({
username: 'admin@example.com',
password: 'password',
clientId: 'test-client',
})
.expect(200);
// Test protected route access
await request(app.getHttpServer())
.get('/admin/dashboard')
.set('Authorization', `Bearer ${loginResponse.body.AccessToken}`)
.expect(200);
});
});
Authentication Testing
// Test authentication using mock service
const response = await request(app.getHttpServer())
.post('/cognito-testing-login')
.send({
username: 'test-user',
password: 'any-password', // Password is not validated in mock mode
clientId: 'mock-client-id'
})
.expect(200);
// Test protected routes
await request(app.getHttpServer())
.get('/protected')
.set('Authorization', `Bearer ${response.body.AccessToken}`)
.expect(200)
.expect({
username: 'test-user',
email: 'test@example.com',
groups: ['users'],
});
Authorization Testing
// Test group-based authorization
describe('Authorization Tests', () => {
it('should allow access to authorized group members', async () => {
// Configure mock user with specific group
await request(app.getHttpServer())
.post('/config')
.send({
enabled: true,
user: {
username: 'admin-user',
email: 'admin@example.com',
groups: ['admin'],
},
})
.expect(200);
// Login and get token
const loginResponse = await request(app.getHttpServer())
.post('/cognito-testing-login')
.send({
username: 'admin@example.com',
password: 'password',
clientId: 'test-client',
})
.expect(200);
// Test protected route access
await request(app.getHttpServer())
.get('/admin/dashboard')
.set('Authorization', `Bearer ${loginResponse.body.AccessToken}`)
.expect(200);
});
});
Advanced Testing
Dynamic User Configuration
Update mock settings during test execution:
await request(app.getHttpServer())
.post('/config')
.send({
user: {
username: 'new-user',
email: 'new@example.com',
groups: ['admin'],
},
})
.expect(200);
Testing Different Token Types
describe('Token Type Tests', () => {
it('should validate ID tokens', async () => {
const response = await request(app.getHttpServer())
.post('/cognito-testing-login')
.send({
username: 'test@example.com',
password: 'password',
clientId: 'test-client',
})
.expect(200);
await request(app.getHttpServer())
.get('/protected')
.set('Authorization', `Bearer ${response.body.IdToken}`)
.expect(200);
});
it('should validate access tokens', async () => {
const response = await request(app.getHttpServer())
.post('/cognito-testing-login')
.send({
username: 'test@example.com',
password: 'password',
clientId: 'test-client',
})
.expect(200);
await request(app.getHttpServer())
.get('/protected')
.set('Authorization', `Bearer ${response.body.AccessToken}`)
.expect(200);
});
});