refactor: add Redis service to CircleCI for E2E tests

- Added Redis container to samples job in CircleCI config
- Removed all mocking from E2E tests to use real Bull queue
- Updated app.module.ts to support environment-based Redis config
- Fixed test routes to match controller (POST /audio/transcode)
- Updated jest-e2e.json with proper timeout and exit settings
- Tests now perform true integration testing with real Redis
This commit is contained in:
som14062005
2025-12-14 18:13:27 +05:30
parent 270f0a710f
commit a189883ec8
4 changed files with 34 additions and 75 deletions

View File

@@ -169,8 +169,12 @@ jobs:
working_directory: ~/nest
docker:
- image: cimg/node:<< pipeline.parameters.maintenance-node-version >>
- image: redis:7-alpine
name: redis
environment:
DISABLE_OPENCOLLECTIVE: 'true'
REDIS_HOST: redis
REDIS_PORT: 6379
steps:
- checkout
- *restore-cache
@@ -179,6 +183,7 @@ jobs:
name: Build all samples
command: npm run build:samples
workflows:
build-and-test:
jobs:
@@ -204,3 +209,4 @@ workflows:
- samples:
requires:
- build

View File

@@ -1,26 +1,15 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from '../../src/app.module';
import { getQueueToken } from '@nestjs/bull';
import { AppModule } from './../../src/app.module';
describe('Audio (e2e)', () => {
describe('AudioController (e2e)', () => {
let app: INestApplication;
// Mock queue that doesn't need Redis
const mockQueue = {
add: jest.fn().mockResolvedValue({ id: 1 }),
process: jest.fn(),
on: jest.fn(),
};
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
})
.overrideProvider(getQueueToken('audio'))
.useValue(mockQueue)
.compile();
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
@@ -30,67 +19,25 @@ describe('Audio (e2e)', () => {
await app.close();
});
describe('POST /audio/transcode', () => {
it('should accept transcode request and return 201', async () => {
const response = await request(app.getHttpServer())
describe('/audio/transcode (POST)', () => {
it('should queue a transcoding job and return success', () => {
return request(app.getHttpServer())
.post('/audio/transcode')
.expect(201);
expect(mockQueue.add).toHaveBeenCalled();
});
it('should queue the job successfully', async () => {
mockQueue.add.mockClear();
await request(app.getHttpServer())
.post('/audio/transcode')
.expect(201);
expect(mockQueue.add).toHaveBeenCalledWith(
'transcode',
expect.objectContaining({ file: expect.any(String) })
);
});
it('should handle multiple concurrent requests', async () => {
mockQueue.add.mockClear();
const requests = Array.from({ length: 5 }, () =>
request(app.getHttpServer()).post('/audio/transcode').expect(201),
);
const requests = [
request(app.getHttpServer()).post('/audio/transcode'),
request(app.getHttpServer()).post('/audio/transcode'),
request(app.getHttpServer()).post('/audio/transcode'),
];
const responses = await Promise.all(requests);
responses.forEach(response => {
expect(response.status).toBe(201);
});
expect(mockQueue.add).toHaveBeenCalledTimes(3);
await Promise.all(requests);
});
});
describe('GET /audio', () => {
it('should return 404 for GET request', async () => {
await request(app.getHttpServer())
.get('/audio')
it('should reject GET requests', () => {
return request(app.getHttpServer())
.get('/audio/transcode')
.expect(404);
});
});
describe('Error Handling', () => {
it('should handle invalid routes', async () => {
await request(app.getHttpServer())
.post('/audio/invalid')
.expect(404);
});
it('should accept POST to transcode endpoint', async () => {
const response = await request(app.getHttpServer())
.post('/audio/transcode');
expect(response.status).toBe(201);
});
});
});

View File

@@ -1,9 +1,12 @@
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": ".",
"testRegex": ".*\\.e2e-spec\\.ts$",
"testEnvironment": "node",
"testRegex": ".e2e-spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"testEnvironment": "node"
"testTimeout": 30000,
"detectOpenHandles": true,
"forceExit": true
}

View File

@@ -1,18 +1,21 @@
import { BullModule } from '@nestjs/bull';
import { Module } from '@nestjs/common';
import { AudioModule } from './audio/audio.module';
import { BullModule } from '@nestjs/bull';
import { AudioController } from './audio/audio.controller';
import { AudioProcessor } from './audio/audio.processor';
@Module({
imports: [
BullModule.forRoot({
redis: {
host: 'localhost',
port: 6379,
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379'),
},
}),
AudioModule,
BullModule.registerQueue({
name: 'audio',
}),
],
controllers: [],
providers: [],
controllers: [AudioController],
providers: [AudioProcessor],
})
export class AppModule {}