├── .gitignore ├── .prettierrc ├── README.md ├── nest-cli.json ├── ormconfig.js ├── package.json ├── src ├── app.controller.spec.ts ├── app.controller.ts ├── app.module.ts ├── app.service.ts ├── main.ts └── user │ ├── user.controller.ts │ ├── user.e2e-spec.ts │ ├── user.entity.ts │ ├── user.module.ts │ └── user.service.ts ├── test ├── app.e2e-spec.ts └── jest-e2e.json ├── tsconfig.build.json ├── tsconfig.json ├── tslint.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Nest Logo 3 |

4 | 5 | ## Description 6 | 7 | A demo of integration tests with NestJS and TypeORM. 8 | -------------------------------------------------------------------------------- /nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "ts", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src" 5 | } 6 | -------------------------------------------------------------------------------- /ormconfig.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | type: 'postgres', 3 | url: 'postgres://paulsalmon:@localhost:5432/e2e_test', 4 | entities: ['src/**/*.entity.ts'], 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nestjs-typeorm-integration-tests", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "", 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "rimraf dist && tsc -p tsconfig.build.json", 9 | "format": "prettier --write \"src/**/*.ts\"", 10 | "start": "ts-node -r tsconfig-paths/register src/main.ts", 11 | "start:dev": "tsc-watch -p tsconfig.build.json --onSuccess \"node dist/main.js\"", 12 | "start:debug": "tsc-watch -p tsconfig.build.json --onSuccess \"node --inspect-brk dist/main.js\"", 13 | "start:prod": "node dist/main.js", 14 | "lint": "tslint -p tsconfig.json -c tslint.json", 15 | "test": "jest", 16 | "test:watch": "jest --watch", 17 | "test:cov": "jest --coverage", 18 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 19 | "test:e2e": "jest --config ./test/jest-e2e.json" 20 | }, 21 | "dependencies": { 22 | "@nestjs/common": "^6.0.0", 23 | "@nestjs/core": "^6.0.0", 24 | "@nestjs/platform-express": "^6.0.0", 25 | "@nestjs/typeorm": "^6.1.3", 26 | "pg": "^7.12.1", 27 | "reflect-metadata": "^0.1.12", 28 | "rimraf": "^2.6.2", 29 | "rxjs": "^6.3.3", 30 | "typeorm": "^0.2.25" 31 | }, 32 | "devDependencies": { 33 | "@nestjs/testing": "6.1.1", 34 | "@types/express": "4.16.1", 35 | "@types/jest": "24.0.11", 36 | "@types/node": "11.13.4", 37 | "@types/supertest": "2.0.7", 38 | "jest": "24.7.1", 39 | "prettier": "1.17.0", 40 | "supertest": "4.0.2", 41 | "ts-jest": "24.0.2", 42 | "ts-node": "8.1.0", 43 | "tsc-watch": "2.2.1", 44 | "tsconfig-paths": "3.8.0", 45 | "tslint": "5.16.0", 46 | "typescript": "3.4.3" 47 | }, 48 | "jest": { 49 | "moduleFileExtensions": [ 50 | "js", 51 | "json", 52 | "ts" 53 | ], 54 | "rootDir": "src", 55 | "testRegex": ".spec.ts$", 56 | "transform": { 57 | "^.+\\.(t|j)s$": "ts-jest" 58 | }, 59 | "coverageDirectory": "../coverage", 60 | "testEnvironment": "node" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let appController: AppController; 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | 14 | appController = app.get(AppController); 15 | }); 16 | 17 | describe('root', () => { 18 | it('should return "Hello World!"', () => { 19 | expect(appController.getHello()).toBe('Hello World!'); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getHello(): string { 10 | return this.appService.getHello(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | 4 | import { AppController } from './app.controller'; 5 | import { AppService } from './app.service'; 6 | import { UserModule } from './user/user.module'; 7 | 8 | @Module({ 9 | imports: [ 10 | UserModule, 11 | TypeOrmModule.forRoot({ 12 | type: 'postgres', 13 | host: 'localhost', 14 | port: 5432, 15 | username: 'paulsalmon', 16 | password: '', 17 | database: 'e2e_test', 18 | entities: ['./**/*.entity.ts'], 19 | synchronize: false, 20 | }), 21 | ], 22 | controllers: [AppController], 23 | providers: [AppService], 24 | }) 25 | export class AppModule {} 26 | -------------------------------------------------------------------------------- /src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './app.module'; 3 | 4 | async function bootstrap() { 5 | const app = await NestFactory.create(AppModule); 6 | await app.listen(3000); 7 | } 8 | bootstrap(); 9 | -------------------------------------------------------------------------------- /src/user/user.controller.ts: -------------------------------------------------------------------------------- 1 | import { Body, Controller, Get, Post } from '@nestjs/common'; 2 | 3 | import { User } from './user.entity'; 4 | import { UserService } from './user.service'; 5 | 6 | @Controller('users') 7 | export class UserController { 8 | constructor(private readonly userService: UserService) {} 9 | 10 | @Get() 11 | list(): Promise { 12 | return this.userService.list(); 13 | } 14 | 15 | @Post() 16 | create(@Body('name') name: string): Promise { 17 | return this.userService.create(name); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/user/user.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { INestApplication } from '@nestjs/common'; 2 | import { Test } from '@nestjs/testing'; 3 | import { TypeOrmModule } from '@nestjs/typeorm'; 4 | import * as supertest from 'supertest'; 5 | import { Repository } from 'typeorm'; 6 | 7 | import { User } from './user.entity'; 8 | import { UserModule } from './user.module'; 9 | 10 | describe('User', () => { 11 | let app: INestApplication; 12 | let repository: Repository; 13 | 14 | beforeAll(async () => { 15 | const module = await Test.createTestingModule({ 16 | imports: [ 17 | UserModule, 18 | TypeOrmModule.forRoot({ 19 | type: 'postgres', 20 | host: 'localhost', 21 | port: 5432, 22 | username: 'paulsalmon', 23 | password: '', 24 | database: 'e2e_test', 25 | entities: ['./**/*.entity.ts'], 26 | synchronize: false, 27 | }), 28 | ], 29 | }).compile(); 30 | 31 | app = module.createNestApplication(); 32 | repository = module.get('UserRepository'); 33 | await app.init(); 34 | }); 35 | 36 | afterEach(async () => { 37 | await repository.query(`DELETE FROM users;`); 38 | }); 39 | 40 | afterAll(async () => { 41 | await app.close(); 42 | }); 43 | 44 | describe('GET /users', () => { 45 | it('should return an array of users', async () => { 46 | await repository.save([{ name: 'test-name-0' }, { name: 'test-name-1' }]); 47 | const { body } = await supertest 48 | .agent(app.getHttpServer()) 49 | .get('/users') 50 | .set('Accept', 'application/json') 51 | .expect('Content-Type', /json/) 52 | .expect(200); 53 | expect(body).toEqual([ 54 | { id: expect.any(Number), name: 'test-name-0' }, 55 | { id: expect.any(Number), name: 'test-name-1' }, 56 | ]); 57 | }); 58 | }); 59 | 60 | describe('POST /users', () => { 61 | it('should return a user', async () => { 62 | const { body } = await supertest 63 | .agent(app.getHttpServer()) 64 | .post('/users') 65 | .set('Accept', 'application/json') 66 | .send({ name: 'test-name' }) 67 | .expect('Content-Type', /json/) 68 | .expect(201); 69 | expect(body).toEqual({ id: expect.any(Number), name: 'test-name' }); 70 | }); 71 | 72 | it('should create a user is the DB', async () => { 73 | await expect(repository.findAndCount()).resolves.toEqual([[], 0]); 74 | await supertest 75 | .agent(app.getHttpServer()) 76 | .post('/users') 77 | .set('Accept', 'application/json') 78 | .send({ name: 'test-name' }) 79 | .expect('Content-Type', /json/) 80 | .expect(201); 81 | await expect(repository.findAndCount()).resolves.toEqual([ 82 | [{ id: expect.any(Number), name: 'test-name' }], 83 | 1, 84 | ]); 85 | }); 86 | 87 | it('should handle a missing name', async () => { 88 | await supertest 89 | .agent(app.getHttpServer()) 90 | .post('/users') 91 | .set('Accept', 'application/json') 92 | .send({ none: 'test-none' }) 93 | .expect('Content-Type', /json/) 94 | .expect(500); 95 | }); 96 | }); 97 | }); 98 | -------------------------------------------------------------------------------- /src/user/user.entity.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; 2 | 3 | @Entity('users') 4 | export class User { 5 | @PrimaryGeneratedColumn('increment') 6 | id: number; 7 | 8 | @Column('varchar') 9 | name: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/user/user.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | 4 | import { UserController } from './user.controller'; 5 | import { User } from './user.entity'; 6 | import { UserService } from './user.service'; 7 | 8 | @Module({ 9 | imports: [TypeOrmModule.forFeature([User])], 10 | controllers: [UserController], 11 | providers: [UserService], 12 | }) 13 | export class UserModule {} 14 | -------------------------------------------------------------------------------- /src/user/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { InjectRepository } from '@nestjs/typeorm'; 3 | import { Repository } from 'typeorm'; 4 | 5 | import { User } from './user.entity'; 6 | 7 | @Injectable() 8 | export class UserService { 9 | constructor( 10 | @InjectRepository(User) 11 | private readonly userRepository: Repository, 12 | ) {} 13 | 14 | list(): Promise { 15 | return this.userRepository.find(); 16 | } 17 | 18 | create(name: string): Promise { 19 | return this.userRepository.save({ name }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import * as request from 'supertest'; 3 | import { AppModule } from './../src/app.module'; 4 | 5 | describe('AppController (e2e)', () => { 6 | let app; 7 | 8 | beforeEach(async () => { 9 | const moduleFixture: TestingModule = await Test.createTestingModule({ 10 | imports: [AppModule], 11 | }).compile(); 12 | 13 | app = moduleFixture.createNestApplication(); 14 | await app.init(); 15 | }); 16 | 17 | it('/ (GET)', () => { 18 | return request(app.getHttpServer()) 19 | .get('/') 20 | .expect(200) 21 | .expect('Hello World!'); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "target": "es2017", 9 | "sourceMap": true, 10 | "outDir": "./dist", 11 | "baseUrl": "./", 12 | "incremental": true 13 | }, 14 | "exclude": [ 15 | "node_modules", 16 | "dist" 17 | ] 18 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": ["tslint:recommended"], 4 | "jsRules": { 5 | "no-unused-expression": true 6 | }, 7 | "rules": { 8 | "quotemark": [true, "single"], 9 | "member-access": [false], 10 | "ordered-imports": [false], 11 | "max-line-length": [true, 150], 12 | "member-ordering": [false], 13 | "interface-name": [false], 14 | "arrow-parens": false, 15 | "object-literal-sort-keys": false 16 | }, 17 | "rulesDirectory": [] 18 | } 19 | --------------------------------------------------------------------------------