From 264c0112b1952523ea3fb52333d68fe431bde19e Mon Sep 17 00:00:00 2001 From: xmlking Date: Thu, 21 Feb 2019 19:04:26 -0800 Subject: [PATCH] style(api): fix lint errors --- angular.json | 18 ++-- apps/api-e2e/jest.config.js | 15 +-- apps/api-e2e/src/app.e2e-spec.ts | 4 +- apps/api-e2e/src/auth/auth.e2e-spec.ts | 78 +++++++++++++++ .../notifications/notifications.e2e-spec.ts | 99 +++++++++++++++++++ apps/api-e2e/tsconfig.e2e.json | 3 +- apps/api-e2e/tslint.json | 33 +------ apps/api/README.md | 29 ++++-- apps/api/src/app/auth/guards/auth.guard.ts | 22 ++--- apps/api/src/app/auth/guards/ws-auth.guard.ts | 22 ++--- .../core/filters/entity-not-found.filter.ts | 2 +- .../external/kubernetes/kubernetes.service.ts | 16 +-- .../notification/notification.service.ts | 3 +- apps/api/src/app/shared/eventbus.gateway.ts | 2 +- apps/api/tsconfig.json | 9 +- apps/api/tsconfig.spec.json | 2 +- apps/api/tslint.json | 33 +------ libs/utils/src/lib/delay-at-least.ts | 10 +- libs/utils/src/lib/wait-until.ts | 2 +- 19 files changed, 267 insertions(+), 135 deletions(-) create mode 100644 apps/api-e2e/src/auth/auth.e2e-spec.ts create mode 100644 apps/api-e2e/src/notifications/notifications.e2e-spec.ts diff --git a/angular.json b/angular.json index 9119239c7..9a9ede800 100644 --- a/angular.json +++ b/angular.json @@ -287,19 +287,21 @@ "root": "apps/api-e2e", "sourceRoot": "apps/api-e2e/src", "projectType": "application", + "prefix": "api", + "schematics": {}, "architect": { - "test": { - "builder": "@nrwl/builders:jest", - "options": { - "jestConfig": "apps/api-e2e/jest.config.js", - "tsConfig": "apps/api-e2e/tsconfig.e2e.json" - } - }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": "apps/api-e2e/tsconfig.e2e.json", - "exclude": ["**/node_modules/**"] + "exclude": ["**/node_modules/**", "**/*.json"] + } + }, + "e2e": { + "builder": "@nrwl/builders:jest", + "options": { + "jestConfig": "apps/api-e2e/jest.config.js", + "tsConfig": "apps/api-e2e/tsconfig.e2e.json" } } } diff --git a/apps/api-e2e/jest.config.js b/apps/api-e2e/jest.config.js index 6f773672b..3db58d54b 100644 --- a/apps/api-e2e/jest.config.js +++ b/apps/api-e2e/jest.config.js @@ -1,17 +1,6 @@ module.exports = { name: 'api-e2e', - testRegex: '.e2e-spec.ts$', - transform: { - '^.+\\.(t|j)s$': 'ts-jest', - }, - moduleFileExtensions: ['js', 'json', 'ts'], - collectCoverage: true, - coverageReporters: ['html'], - testEnvironment: 'node', + preset: '../../jest.config.js', + testMatch: ['**/+(*.)+(e2e-spec|e2e-test).+(ts|js)?(x)'], coverageDirectory: '../../coverage/apps/api-e2e', - globals: { - 'ts-jest': { - tsConfig: 'apps/api-e2e/tsconfig.e2e.json', - }, - }, }; diff --git a/apps/api-e2e/src/app.e2e-spec.ts b/apps/api-e2e/src/app.e2e-spec.ts index ba341776e..7e2ad4046 100755 --- a/apps/api-e2e/src/app.e2e-spec.ts +++ b/apps/api-e2e/src/app.e2e-spec.ts @@ -2,7 +2,7 @@ import * as request from 'supertest'; import { Test } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; // @ts-ignore -import { AppModule } from '../../api/src/app/app.module'; +// import { AppModule } from '../../api/src/app/app.module'; jest.setTimeout(30000); @@ -11,7 +11,7 @@ describe('AppController (e2e)', () => { beforeAll(async () => { const moduleFixture = await Test.createTestingModule({ - imports: [AppModule], + // imports: [AppModule], }).compile(); app = moduleFixture.createNestApplication(); diff --git a/apps/api-e2e/src/auth/auth.e2e-spec.ts b/apps/api-e2e/src/auth/auth.e2e-spec.ts new file mode 100644 index 000000000..8686e14a4 --- /dev/null +++ b/apps/api-e2e/src/auth/auth.e2e-spec.ts @@ -0,0 +1,78 @@ +// import 'jest'; +// import * as supertest from 'supertest'; +// import { Test } from '@nestjs/testing'; +// import { INestApplication } from '@nestjs/common'; +// +// import { AuthModule } from '../../src/auth/auth.module'; +// import { AuthService } from '../../src/auth/auth.service'; +// import { AuthenticateDto } from '../../src/auth/dto/authenticate-dto'; +// import { users } from '../../src/auth/users.const'; +// +// describe('Auth', () => { +// let app: INestApplication; +// +// // +// // Setup mock data & services +// // +// const regularUser = users.find(user => user.username === 'user@mydomain.com'); +// let regularUserJWTToken: any; +// const staffUser = users.find(user => user.username === 'staff@mydomain.com'); +// let staffUserJWTToken: any; +// +// beforeAll(async () => { +// // +// // Instantiate nest application +// // +// const module = await Test.createTestingModule({ +// imports: [AuthModule], +// }).compile(); +// +// app = module.createNestApplication(); +// await app.init(); +// +// supertest(app.getHttpServer()) +// .post('/api/auth/authenticate') +// .send({ authenticateDto: { username: regularUser.username, password: regularUser.password } }) +// .end((err, res) => { +// regularUserJWTToken = JSON.parse(res.text).data; +// }); +// +// supertest(app.getHttpServer()) +// .post('/api/auth/authenticate') +// .send({ authenticateDto: { username: staffUser.username, password: staffUser.password } }) +// .end((err, res) => { +// staffUserJWTToken = JSON.parse(res.text).data; +// }); +// }); +// +// it(`/POST auth`, () => { +// return supertest(app.getHttpServer()) +// .post('/api/auth/authenticate') +// .send({ authenticateDto: { username: regularUser.username, password: regularUser.password } }) +// .expect(201); +// }); +// +// it(`/GET protected data without auth token`, () => { +// return supertest(app.getHttpServer()) +// .get('/api/auth/data') +// .expect(401); +// }); +// +// it(`/GET protected data with wrong role`, () => { +// return supertest(app.getHttpServer()) +// .get('/api/auth/data') +// .set('authorization', `Bearer ${regularUserJWTToken.accessToken}`) +// .expect(403); +// }); +// +// it(`/GET protected data with correct role`, () => { +// return supertest(app.getHttpServer()) +// .get('/api/auth/data') +// .set('authorization', `Bearer ${staffUserJWTToken.accessToken}`) +// .expect(200); +// }); +// +// afterAll(async () => { +// await app.close(); +// }); +// }); diff --git a/apps/api-e2e/src/notifications/notifications.e2e-spec.ts b/apps/api-e2e/src/notifications/notifications.e2e-spec.ts new file mode 100644 index 000000000..7a4fec062 --- /dev/null +++ b/apps/api-e2e/src/notifications/notifications.e2e-spec.ts @@ -0,0 +1,99 @@ +// import 'jest'; +// import * as supertest from 'supertest'; +// import { Test } from '@nestjs/testing'; +// import { CatsModule } from '../../src/cats/cats.module'; +// import { INestApplication } from '@nestjs/common'; +// import { AuthService } from '../../src/auth/auth.service'; +// import { AccessTokenWithMetadata } from '../../src/auth/interfaces/jwt-accessTokenData.interface'; +// import { users } from '../../src/auth/users.const'; +// import { ConfigService } from '../../src/common/services/config.service'; +// import { CatsService } from '../../src/cats/cats.service'; +// +// describe('Notifications', () => { +// let app: INestApplication; +// let userAuthToken: AccessTokenWithMetadata; +// let staffAuthToken: AccessTokenWithMetadata; +// const configService = new ConfigService(); +// +// // +// // Set configuration flags +// // +// configService.nodeEnv = 'test'; +// +// // +// // Setup mock data & services +// // +// const userJwtPayload = { +// user: users.find(user => user.username === 'user@mydomain.com'), +// }; +// +// const staffJwtPayload = { +// user: users.find(user => user.username === 'staff@mydomain.com'), +// }; +// +// const catsService = { findAll: () => ['test'] }; +// +// beforeAll(async () => { +// // +// // Instantiate nest application +// // +// const module = await Test.createTestingModule({ +// imports: [CatsModule], +// }) +// .overrideProvider(CatsService) +// .useValue(catsService) +// .compile(); +// +// app = module.createNestApplication(); +// await app.init(); +// +// userAuthToken = await app.get(AuthService).createToken(userJwtPayload); +// staffAuthToken = await app.get(AuthService).createToken(staffJwtPayload); +// }); +// +// it(`/GET cats`, () => { +// return supertest(app.getHttpServer()) +// .get('/api/cats') +// .expect(200) +// .expect({ +// data: catsService.findAll(), +// }); +// }); +// +// it(`/GET cats with auth token`, () => { +// return supertest(app.getHttpServer()) +// .get('/api/cats') +// .set('authorization', `Bearer ${userAuthToken}`) +// .expect(200) +// .expect({ +// data: catsService.findAll(), +// }); +// }); +// +// it(`/GET protected cats without auth token`, () => { +// return supertest(app.getHttpServer()) +// .get('/api/cats/protected') +// .expect(401); +// }); +// +// it(`/GET protected cats with user auth token`, () => { +// return supertest(app.getHttpServer()) +// .get('/api/cats/protected') +// .set('authorization', `Bearer ${userAuthToken.accessToken}`) +// .expect(403); +// }); +// +// it(`/GET protected cats with staff auth token`, () => { +// return supertest(app.getHttpServer()) +// .get('/api/cats/protected') +// .set('authorization', `Bearer ${staffAuthToken.accessToken}`) +// .expect(200) +// .expect({ +// data: catsService.findAll(), +// }); +// }); +// +// afterAll(async () => { +// await app.close(); +// }); +// }); diff --git a/apps/api-e2e/tsconfig.e2e.json b/apps/api-e2e/tsconfig.e2e.json index 90aa9dbfa..42ec60d46 100644 --- a/apps/api-e2e/tsconfig.e2e.json +++ b/apps/api-e2e/tsconfig.e2e.json @@ -3,8 +3,7 @@ "compilerOptions": { "outDir": "../../dist/apps/api-e2e", "module": "commonjs", - "target": "es6", "types": ["jest", "node"] }, - "include": ["**/*.ts"] + "include": ["**/*.e2e-spec.ts", "**/*.d.ts"] } diff --git a/apps/api-e2e/tslint.json b/apps/api-e2e/tslint.json index 4738f144d..7fb9af0c4 100755 --- a/apps/api-e2e/tslint.json +++ b/apps/api-e2e/tslint.json @@ -1,30 +1,7 @@ { - "defaultSeverity": "error", - "extends": ["tslint:recommended"], - "jsRules": { - "no-unused-expression": true - }, - "rules": { - "eofline": false, - "quotemark": [true, "single"], - "indent": false, - "member-access": [false], - "ordered-imports": [false], - "max-line-length": [true, 150], - "member-ordering": [false], - "curly": false, - "interface-name": [false], - "array-type": [false], - "no-console": false, - "no-empty-interface": false, - "no-empty": false, - "arrow-parens": false, - "object-literal-sort-keys": false, - "no-unused-expression": false, - "max-classes-per-file": [false], - "variable-name": [false], - "one-line": [false], - "one-variable-per-declaration": [false] - }, - "rulesDirectory": [] + "extends": "../../tslint.json", + "rules": {}, + "jsRules":{ + "object-literal-sort-keys": false + } } diff --git a/apps/api/README.md b/apps/api/README.md index f3e683037..94fa85170 100755 --- a/apps/api/README.md +++ b/apps/api/README.md @@ -57,10 +57,12 @@ ng serve api --prod #### Run Prod Mode ```bash -# build first +# clean dist first +npx rimraf dist +# then build ng build api --prod # then run -npm run api:start:prod +node dist/apps/api/main.js ``` **API URL:** http://localhost:3000 @@ -72,7 +74,7 @@ npm run api:start:prod > build for production env ```bash -npm run api:build +ng build api --prod ``` ### Generate @@ -92,16 +94,27 @@ nest g class user.entity app/auth --no-spec --dry-run nest g class auth.exception app/auth --no-spec --dry-run ``` -### Test +### Unit Test > coverage will be generate in coverage/apps/api ```bash -# unit tests -ng test api +# unit test only changed +ng test api --onlyChanged +# generate coverage +ng test api --codeCoverage +# test in CI env +ng test api --runInBand +``` -# e2e tests -ng test api-e2e +### E2E Test + +```bash +ng e2e api-e2e +# e2e test with watch mode +ng e2e api-e2e --watch +# e2e test in CI env +ng e2e api-e2e --forceExit --detectOpenHandles ``` ### Reference diff --git a/apps/api/src/app/auth/guards/auth.guard.ts b/apps/api/src/app/auth/guards/auth.guard.ts index 93023f506..300576e7c 100644 --- a/apps/api/src/app/auth/guards/auth.guard.ts +++ b/apps/api/src/app/auth/guards/auth.guard.ts @@ -15,6 +15,17 @@ export const defaultOptions = { }, }; +const createPassportContext = (request, response) => (type, options) => + new Promise((resolve, reject) => + passport.authenticate(type, options, (err, user, info) => { + try { + return resolve(options.callback(err, user, info)); + } catch (err) { + reject(err); + } + })(request, response, resolve), + ); + // TODO like https://github.com/nestjs/nest/blob/master/sample/19-auth/src/auth/guards/jwt-auth.guard.ts @Injectable() export class AuthGuard implements CanActivate { @@ -30,14 +41,3 @@ export class AuthGuard implements CanActivate { return true; } } - -const createPassportContext = (request, response) => (type, options) => - new Promise((resolve, reject) => - passport.authenticate(type, options, (err, user, info) => { - try { - return resolve(options.callback(err, user, info)); - } catch (err) { - reject(err); - } - })(request, response, resolve), - ); diff --git a/apps/api/src/app/auth/guards/ws-auth.guard.ts b/apps/api/src/app/auth/guards/ws-auth.guard.ts index ccfadbc08..418c11821 100644 --- a/apps/api/src/app/auth/guards/ws-auth.guard.ts +++ b/apps/api/src/app/auth/guards/ws-auth.guard.ts @@ -15,6 +15,17 @@ export const defaultWsOptions = { }, }; +const createPassportContext = (request, response) => (type, options) => + new Promise((resolve, reject) => + passport.authenticate(type, options, (err, user, info) => { + try { + return resolve(options.callback(err, user, info)); + } catch (err) { + reject(err); + } + })(request, response, resolve), + ); + @Injectable() export class WsAuthGuard implements CanActivate { constructor() {} @@ -35,14 +46,3 @@ export class WsAuthGuard implements CanActivate { } } } - -const createPassportContext = (request, response) => (type, options) => - new Promise((resolve, reject) => - passport.authenticate(type, options, (err, user, info) => { - try { - return resolve(options.callback(err, user, info)); - } catch (err) { - reject(err); - } - })(request, response, resolve), - ); diff --git a/apps/api/src/app/core/filters/entity-not-found.filter.ts b/apps/api/src/app/core/filters/entity-not-found.filter.ts index 3548904e9..b81d1b870 100644 --- a/apps/api/src/app/core/filters/entity-not-found.filter.ts +++ b/apps/api/src/app/core/filters/entity-not-found.filter.ts @@ -3,7 +3,7 @@ import { ArgumentsHost, Catch, ExceptionFilter, NotFoundException } from '@nestj @Catch(EntityNotFoundError) export class EntityNotFoundFilter implements ExceptionFilter { - catch(exception: EntityNotFoundError, _host: ArgumentsHost) { + catch(exception: EntityNotFoundError, host: ArgumentsHost) { throw new NotFoundException(exception.message); } } diff --git a/apps/api/src/app/external/kubernetes/kubernetes.service.ts b/apps/api/src/app/external/kubernetes/kubernetes.service.ts index a1337d20e..1989bf1b2 100644 --- a/apps/api/src/app/external/kubernetes/kubernetes.service.ts +++ b/apps/api/src/app/external/kubernetes/kubernetes.service.ts @@ -60,7 +60,7 @@ export class KubernetesService implements OnModuleInit { const namespaces = await this.clients.get(cluster).api.v1.namespaces.get(); return namespaces.body.items; } catch (error) { - KubernetesService.handleError(error); + this.handleError(error); } } @@ -70,7 +70,7 @@ export class KubernetesService implements OnModuleInit { const namespaces = await this.clients.get(cluster).api.v1.namespaces.get(); return namespaces.items; } catch (error) { - KubernetesService.handleError(error); + this.handleError(error); } } @@ -82,7 +82,7 @@ export class KubernetesService implements OnModuleInit { .get(); return namespace1.body; } catch (error) { - KubernetesService.handleError(error); + this.handleError(error); } } @@ -94,7 +94,7 @@ export class KubernetesService implements OnModuleInit { .serviceaccounts.get(); return namespaces.body.items; } catch (error) { - KubernetesService.handleError(error); + this.handleError(error); } } @@ -106,12 +106,14 @@ export class KubernetesService implements OnModuleInit { .get(); return !!foundNamespace; } catch (error) { - if (error.code === 404) return false; - KubernetesService.handleError(error); + if (error.code === 404) { + return false; + } + this.handleError(error); } } - static handleError(error: Error & { code?: number; statusCode?: number }) { + private handleError(error: Error & { code?: number; statusCode?: number }) { const message = error.message || 'unknown error'; const statusCode = error.statusCode || error.code || HttpStatus.I_AM_A_TEAPOT; console.log(message, statusCode); diff --git a/apps/api/src/app/notifications/notification/notification.service.ts b/apps/api/src/app/notifications/notification/notification.service.ts index 51e4c627b..4ac67da3d 100644 --- a/apps/api/src/app/notifications/notification/notification.service.ts +++ b/apps/api/src/app/notifications/notification/notification.service.ts @@ -49,7 +49,8 @@ export class NotificationService extends CrudService implements On vibrate: [200, 100, 200], }; - let subscriptions: Subscription[], count: number; + let subscriptions: Subscription[]; + let count: number; switch (notification.targetType) { case TargetType.USER: [subscriptions, count] = await this.subscriptionService.findAndCount({ userId: notification.target }); diff --git a/apps/api/src/app/shared/eventbus.gateway.ts b/apps/api/src/app/shared/eventbus.gateway.ts index 5cabf53ae..074e0818c 100644 --- a/apps/api/src/app/shared/eventbus.gateway.ts +++ b/apps/api/src/app/shared/eventbus.gateway.ts @@ -17,9 +17,9 @@ import { AuthService, User, WsAuthGuard } from '../auth'; @WebSocketGateway({ namespace: 'eventbus' }) export class EventBusGateway extends EventEmitter implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect { - private readonly logger = new Logger(EventBusGateway.name); static EVENTS = 'events'; static ACTIONS = 'actions'; + private readonly logger = new Logger(EventBusGateway.name); @WebSocketServer() server: Server; diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json index 6ad7ee9f7..2bae24ff8 100644 --- a/apps/api/tsconfig.json +++ b/apps/api/tsconfig.json @@ -2,11 +2,8 @@ "extends": "../../tsconfig.json", "compilerOptions": { "types": [ - "node", - "jest" + "jest", + "node" ] - }, - "include": [ - "**/*.ts" - ] + } } diff --git a/apps/api/tsconfig.spec.json b/apps/api/tsconfig.spec.json index ff37f6ad3..a4bad20ea 100644 --- a/apps/api/tsconfig.spec.json +++ b/apps/api/tsconfig.spec.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "../../dist/out-tsc/apps/api", + "outDir": "../../dist/apps/api", "module": "commonjs", "types": ["jest", "node"] }, diff --git a/apps/api/tslint.json b/apps/api/tslint.json index 4738f144d..7fb9af0c4 100755 --- a/apps/api/tslint.json +++ b/apps/api/tslint.json @@ -1,30 +1,7 @@ { - "defaultSeverity": "error", - "extends": ["tslint:recommended"], - "jsRules": { - "no-unused-expression": true - }, - "rules": { - "eofline": false, - "quotemark": [true, "single"], - "indent": false, - "member-access": [false], - "ordered-imports": [false], - "max-line-length": [true, 150], - "member-ordering": [false], - "curly": false, - "interface-name": [false], - "array-type": [false], - "no-console": false, - "no-empty-interface": false, - "no-empty": false, - "arrow-parens": false, - "object-literal-sort-keys": false, - "no-unused-expression": false, - "max-classes-per-file": [false], - "variable-name": [false], - "one-line": [false], - "one-variable-per-declaration": [false] - }, - "rulesDirectory": [] + "extends": "../../tslint.json", + "rules": {}, + "jsRules":{ + "object-literal-sort-keys": false + } } diff --git a/libs/utils/src/lib/delay-at-least.ts b/libs/utils/src/lib/delay-at-least.ts index 508e4d9ae..a3c07b11d 100644 --- a/libs/utils/src/lib/delay-at-least.ts +++ b/libs/utils/src/lib/delay-at-least.ts @@ -1,10 +1,8 @@ -import { Observable, of } from 'rxjs'; -import { combineLatest, delay } from 'rxjs/operators'; +import { combineLatest, Observable, of } from 'rxjs'; +import { delay, map } from 'rxjs/operators'; export function delayAtLeast(minDelay: number): (s$: Observable) => Observable { return (s$: Observable): Observable => - of(true).pipe( - delay(minDelay), - combineLatest(s$, (_, s) => s), - ); + combineLatest(of(true).pipe(delay(minDelay)), s$) + .pipe(map(([_, i]) => i)); } diff --git a/libs/utils/src/lib/wait-until.ts b/libs/utils/src/lib/wait-until.ts index c4e495c4c..122bb7ef9 100644 --- a/libs/utils/src/lib/wait-until.ts +++ b/libs/utils/src/lib/wait-until.ts @@ -1,5 +1,5 @@ export function waitUntil(condition, timeout = 2000) { - return new Promise(function(resolve, reject) { + return new Promise((resolve, reject) => { setTimeout(_ => reject(), timeout); function loop() {