Skip to content

Commit

Permalink
test: add integration test for passport module
Browse files Browse the repository at this point in the history
  • Loading branch information
jmcdo29 committed Feb 9, 2022
1 parent f46873b commit 3550707
Show file tree
Hide file tree
Showing 12 changed files with 7,097 additions and 2,087 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ npm-debug.log
.DS_Store

# tests
/test
/coverage
/.nyc_output

Expand Down
10 changes: 10 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
moduleFileExtensions: ['js', 'json', 'ts'],
rootDir: '.',
testMatch: ['<rootDir>/test/*.e2e-spec.ts'],
transform: {
'^.+\\.ts$': 'ts-jest'
},
testEnvironment: 'node',
collectCoverage: true
};
8,941 changes: 6,868 additions & 2,073 deletions package-lock.json

Large diffs are not rendered by default.

19 changes: 16 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
"author": "Kamil Mysliwiec",
"license": "MIT",
"scripts": {
"build": "rimraf dist && tsc -p tsconfig.json",
"build": "rimraf dist && tsc -p tsconfig.build.json",
"format": "prettier --write \"lib/**/*.ts\"",
"lint": "eslint 'lib/**/*.ts' --fix",
"precommit": "lint-staged",
"prepublish:npm": "npm run build",
"publish:npm": "npm publish --access public",
"prerelease": "npm run build",
"release": "release-it"
"release": "release-it",
"test": "jest"
},
"peerDependencies": {
"@nestjs/common": "^6.0.0 || ^7.0.0 || ^8.0.0",
Expand All @@ -22,21 +23,33 @@
"@commitlint/cli": "16.1.0",
"@commitlint/config-angular": "16.0.0",
"@nestjs/common": "8.2.6",
"@nestjs/core": "^8.2.6",
"@nestjs/jwt": "^8.0.0",
"@nestjs/platform-express": "^8.2.6",
"@nestjs/testing": "^8.2.6",
"@types/jest": "^27.4.0",
"@types/node": "16.11.22",
"@types/passport": "1.0.7",
"@types/passport-jwt": "^3.0.6",
"@types/passport-local": "^1.0.34",
"@typescript-eslint/eslint-plugin": "5.11.0",
"@typescript-eslint/parser": "5.11.0",
"eslint": "8.8.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-import": "2.25.4",
"husky": "7.0.4",
"lint-staged": "12.3.3",
"jest": "^27.5.0",
"pactum": "^3.1.3",
"passport": "0.5.2",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"prettier": "2.5.1",
"release-it": "14.12.4",
"reflect-metadata": "0.1.13",
"release-it": "14.12.4",
"rimraf": "3.0.2",
"rxjs": "7.5.3",
"ts-jest": "^27.1.3",
"typescript": "4.5.5"
},
"lint-staged": {
Expand Down
28 changes: 28 additions & 0 deletions test/app.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Body, Controller, Get, Post, Req, UseGuards } from '@nestjs/common';
import { AuthGuard } from '../lib';

import { AppService } from './app.service';

@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello() {
return this.appService.getHello();
}

@UseGuards(AuthGuard('jwt'))
@Get('private')
getPrivateHello() {
return this.appService.getPrivateMessage();
}

@UseGuards(AuthGuard('local'))
@Post('login')
login(@Req() req: any, @Body() body: Record<string, string>) {
return this.appService.getToken({
username: body.username,
id: req.user.id
});
}
}
50 changes: 50 additions & 0 deletions test/app.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { spec, request } from 'pactum';
import { AppModule } from './app.module';

describe('Passport Module', () => {
let app: INestApplication;

beforeAll(async () => {
const modRef = await Test.createTestingModule({
imports: [AppModule]
}).compile();
app = modRef.createNestApplication();
await app.listen(0);
const url = (await app.getUrl()).replace('[::1]', 'localhost');
request.setBaseUrl(url);
});

describe('Authenticated flow', () => {
it('should be able to log in and get a jwt, then hit the secret route', async () => {
await spec()
.post('/login')
.withBody({ username: 'test1', password: 'test' })
.expectStatus(201)
.stores('token', 'token');
await spec()
.get('/private')
.withHeaders('Authorization', 'Bearer $S{token}')
.expectBody({ message: 'Hello secure world!' });
});
});
describe('UnauthenticatedFlow', () => {
it('should return a 401 for an invalid login', async () => {
await spec()
.post('/login')
.withBody({ username: 'test1', password: 'not the right password' })
.expectStatus(401);
});
it('should return a 401 for an invalid JWT', async () => {
await spec()
.get('/private')
.withHeaders('Authorization', 'Bearer not-a-jwt')
.expectStatus(401);
});
});

afterAll(async () => {
await app.close();
});
});
19 changes: 19 additions & 0 deletions test/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '../lib';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { JwtStrategy } from './jwt.strategy';
import { LocalStrategy } from './local.strategy';

@Module({
controllers: [AppController],
imports: [
JwtModule.register({
secret: 's3cr3t'
}),
PassportModule.register({})
],
providers: [AppService, LocalStrategy, JwtStrategy]
})
export class AppModule {}
47 changes: 47 additions & 0 deletions test/app.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
ForbiddenException,
Injectable,
UnauthorizedException
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AppService {
private users = [
{
id: '1',
username: 'test1',
password: 'test'
},
{
id: '2',
username: 'nottest1',
password: 'secret'
}
];
constructor(private readonly jwtService: JwtService) {}
getHello() {
return { message: 'Hello open world!' };
}

getPrivateMessage() {
return { message: 'Hello secure world!' };
}

getToken({ username, id }: { username: string; id: string }): {
token: string;
} {
return { token: this.jwtService.sign({ username, id }) };
}

findUser({ username, password }: { username: string; password: string }): {
id: string;
username: string;
} {
const user = this.users.find((u) => u.username === username);
if (!user || user.password !== password) {
return null;
}
return user;
}
}
17 changes: 17 additions & 0 deletions test/jwt.strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Injectable } from '@nestjs/common';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '../lib';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 's3cr3t'
});
}

validate(payload) {
return { id: payload.id, email: payload.email };
}
}
14 changes: 14 additions & 0 deletions test/local.strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Injectable } from '@nestjs/common';
import { Strategy } from 'passport-local';
import { PassportStrategy } from '../lib';
import { AppService } from './app.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private readonly appService: AppService) {
super();
}
validate(username: string, password: string) {
return this.appService.findUser({ username, password });
}
}
24 changes: 24 additions & 0 deletions tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es6",
"sourceMap": false,
"outDir": "./dist",
"rootDir": "./lib",
"skipLibCheck": true
},
"include": [
"lib/**/*",
"../index.ts"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
14 changes: 4 additions & 10 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,9 @@
"target": "es6",
"sourceMap": false,
"outDir": "./dist",
"rootDir": "./lib",
"rootDir": "./",
"skipLibCheck": true
},
"include": [
"lib/**/*",
"../index.ts"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
"include": ["lib/**/*", "../index.ts", "test/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"]
}

0 comments on commit 3550707

Please sign in to comment.