I've got a controller configured in NestJS and I want to check that the appropriate guards are set - does anyone have an example of how it could be done?
This (abridged) example works correctly as an application so I'm only after guidance on testing.
You'll notice in the user test there are tests where I'm calling Reflect.getMetadata
. I'm after something like this - when I check it on the __guards__
metadata, this is a function and I'm struggling to mock it out so I can check that it's applied with AuthGuard('jwt')
as it's setting.
User.controller.ts
@Controller('/api/user')
export class UserController {
@UseGuards(AuthGuard('jwt'))
@Get()
user(@Request() req) {
return req.user;
}
}
User.controller.spec.ts
describe('User Controller', () => {
// beforeEach setup as per the cli generator
describe('#user', () => {
beforeEach(() => {
// This is how I'm checking the @Get() decorator is applied correctly - I'm after something for __guards__
expect(Reflect.getMetadata('path', controller.user)).toBe('/');
expect(Reflect.getMetadata('method', controller.user)).toBe(RequestMethod.GET);
});
it('should return the user', () => {
const req = {
user: 'userObj',
};
expect(controller.user(req)).toBe(req.user);
});
});
});
Authorization guard The AuthGuard that we'll build now assumes an authenticated user (and that, therefore, a token is attached to the request headers). It will extract and validate the token, and use the extracted information to determine whether the request can proceed or not.
We can write an unit test for this controller method by following steps: Create the test data which is returned when our service method is called. We use a concept called test data builder when we are creating the test data for our test.
For TypeScript, unit tests are run against the generated JavaScript code. In most TypeScript scenarios, you can debug a unit test by setting a breakpoint in TypeScript code, right-clicking a test in Test Explorer, and choosing Debug.
Unit testing focuses on writing tests for the smallest possible units. In most cases, they are functions defined in classes. MethodA in a class may be calling MethodB in another class. However, a unit test of MethodA is focused only on the logic of MethodA, not MethodB.
We will use Jest as Runner for Running tests for NestJS Lets first talk about Jest a little bit which is a popular test runner Jest is a JavaScript test runner, that is, a JavaScript library for creating, running, and structuring tests. Jest ships as an NPM package, you can install it in any JavaScript project.
If you are just looking to test the guard, you can instantiate the GuardClass directly and test its canActivate method by providing an ExecutionContext object. I've got an example here. The example uses a library that creates mock objects for you (since then renamed ), but the idea of it is that you'd create an object like
If you're wanting to test that when you call the route the guard is executed, then you need to set up supertest to make the call to the route. Maybe I'm not understanding what you're looking to do
For what it's worth, you shouldn't need to test that the decorators provided by the framework set what you expect them too. That's why the framework has tests on them to begin with. Nevertheless, if you want to check that the decorator actually sets the expected metadata you can see that done here.
If you are just looking to test the guard, you can instantiate the GuardClass directly and test its canActivate
method by providing an ExecutionContext
object. I've got an example here. The example uses a library that creates mock objects for you (since then renamed), but the idea of it is that you'd create an object like
const mockExecutionContext: Partial<
Record<
jest.FunctionPropertyNames<ExecutionContext>,
jest.MockedFunction<any>
>
> = {
switchToHttp: jest.fn().mockReturnValue({
getRequest: jest.fn(),
getResponse: jest.fn(),
}),
};
Where getRequest
and getResponse
return HTTP Request and Response objects (or at least partials of them). To just use this object, you'll need to also use as any
to keep Typescript from complaining too much.
I realize its not quite the answer you are looking for, but building on @Jay McDoniel's answer I used the following to test a custom decorator's existence on a controller function (although i'm not 100% sure if this is the correct way to test this for non-custom guards)
import { Controller } from '@nestjs/common';
import { UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from './jwtAuthGuard';
@Controller()
export class MyController {
@UseGuards(JwtAuthGuard)
user() {
...
}
}
it('should ensure the JwtAuthGuard is applied to the user method', async () => {
const guards = Reflect.getMetadata('__guards__', MyController.prototype.user)
const guard = new (guards[0])
expect(guard).toBeInstanceOf(JwtAuthGuard)
});
And for controllers
it('should ensure the JwtAuthGuard is applied to the controller', async () => {
const guards = Reflect.getMetadata('__guards__', MyController)
const guard = new (guards[0])
expect(guard).toBeInstanceOf(JwtAuthGuard)
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With