A middleware function retrieves a JSON document from a microservice endpoint and appends it to the request.
The good path test is successful, but I'm struggling to make the bad path test throw a ForbiddenException and stop it from invoking next().
When not in a Jest test environment, the middleware will block a request if it fails to fetch the JSON document.
Any assistance would be greatly appreciated :)
Middleware:
import { ForbiddenException, Injectable, NestMiddleware } from '@nestjs/common'
import { HttpService } from '@nestjs/axios'
import { NextFunction, Request, Response } from 'express'
import { catchError, firstValueFrom } from 'rxjs'
import { LoggerService } from '../logger.service'
@Injectable()
export class MyMiddleware implements NestMiddleware {
constructor(
private logger: LoggerService,
private httpService: HttpService,
) {}
async use(req: Request, res: Response, next: NextFunction) {
const response = await firstValueFrom(
this.httpService
.get('https://myservice/document-endpoint', {
headers: {
Cookie: req.headers['cookie'],
},
})
.pipe(
catchError((error: Error) => {
this.logger.error(error.message);
throw new ForbiddenException()
}),
),
)
req.document = response.data.value
next()
}
}
Tests:
The issue lies with the 'Bad path' test... the nextFunction method continues to get called and I can't figure out how to trigger the error.
import { MyMiddleware } from './mymiddleware'
import { NextFunction, Request, Response } from 'express'
import { LoggerService } from '../logger/logger.service'
import { of } from 'rxjs'
import { createMock } from '@golevelup/nestjs-testing'
import { HttpService } from '@nestjs/axios'
import { AxiosResponse } from 'axios'
describe('Authorization middleware', () => {
let middleware: MyMiddleware
let mockRequest: Partial<Request>
let mockResponse: Partial<Response>
let nextFunction: NextFunction = jest.fn()
let mockHttpService = createMock<HttpService>()
mockRequest = {
headers: {
cookie: 'idToken=asdasd'
}
beforeEach(async () => {
mockResponse = {
json: jest.fn(),
}
middleware = new MyMiddleware(new LoggerService(), mockHttpService)
})
test('bad path', async () => {
jest.clearAllMocks()
const mockDocumentResponse: AxiosResponse = {
status: 404,
statusText: '',
headers: {},
config: {},
data: { error: 'Not Found' }
}
const httpSpy = jest.spyOn(mockHttpService, 'get')
.mockReturnValue(of(mockDocumentResponse))
await middleware.use(mockRequest as Request, mockResponse as Response, nextFunction)
expect(nextFunction).toBeCalledTimes(0)
})
test('good path', async () => {
jest.clearAllMocks()
const mockDocumentResponse: AxiosResponse = {
status: 200,
statusText: '',
headers: {},
config: {},
data: {
value: 'example document',
}
}
jest.spyOn(mockHttpService, 'get').mockImplementationOnce(() => of(mockDocumentResponse));
await middleware.use(mockRequest as Request, mockResponse as Response, nextFunction)
expect(nextFunction).toBeCalledTimes(1)
})
})