Skip to content

Commit

Permalink
Merge pull request #8 from Cophr/ci/enhance-lint-rules
Browse files Browse the repository at this point in the history
ci/enhance lint rules
  • Loading branch information
moontai0724 authored Jun 10, 2023
2 parents 2f13ea2 + 9345a8f commit 2921cba
Show file tree
Hide file tree
Showing 29 changed files with 488 additions and 264 deletions.
31 changes: 0 additions & 31 deletions .eslintrc.js

This file was deleted.

106 changes: 106 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint/eslint-plugin",
"simple-import-sort",
"import"
],
"extends": [
"eslint:all",
"plugin:@typescript-eslint/all",
"plugin:typescript-sort-keys/recommended",
"prettier"
],
"root": true,
"env": {
"node": true,
"jest": true
},
"ignorePatterns": [".eslintrc.js"],
"rules": {
// disabled rules (required)
"no-void": "off", // To call promise functions without other actions
"no-magic-numbers": "off", // This will wrongly detect a number passed to a function as a magic number
"@typescript-eslint/no-magic-numbers": "off",
"new-cap": "off", // The decorators will be wrongly detected
"class-methods-use-this": "off", // some methods are not using this
"require-await": "off", // it will wrongly detect async methods as not having await
"@typescript-eslint/require-await": "off",
"max-params": "off", // injection constructors need many parameters

// disabled rules (optional, in personal preference)
"no-console": "off", // This will disable console.log, console.error, etc. This could be removed if we have our own logger
"one-var": "off", // in favor to not merge variables to one
"no-continue": "off", // in favor to use continue

// disabled typescript-eslint rules (too strict)
"@typescript-eslint/promise-function-async": "off",
"@typescript-eslint/explicit-member-accessibility": "off",
"@typescript-eslint/prefer-readonly-parameter-types": "off",
"@typescript-eslint/parameter-properties": "off",
"@typescript-eslint/no-extraneous-class": "off",
"@typescript-eslint/no-misused-promises": "off",
"@typescript-eslint/member-ordering": "off",
"@typescript-eslint/no-type-alias": "off",
"@typescript-eslint/unbound-method": "off",
"@typescript-eslint/strict-boolean-expressions": "off",

// modified rules
"func-style": ["error", "declaration", { "allowArrowFunctions": true }],

// replaced rules
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": "error",

"no-shadow": "off",
"@typescript-eslint/no-shadow": "error",

"sort-imports": "off",
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"import/first": "error",
"import/newline-after-import": "error",
"import/no-duplicates": "error",

// additional rules
"@typescript-eslint/consistent-type-exports": "error",
"@typescript-eslint/consistent-type-imports": [
"error",
{
"fixStyle": "inline-type-imports"
}
],

"padding-line-between-statements": [
"error",
{ "blankLine": "always", "prev": "*", "next": "return" },
{
"blankLine": "always",
"prev": ["const", "let", "var", "multiline-expression"],
"next": "*"
},
{
"blankLine": "any",
"prev": ["const", "let", "var"],
"next": ["const", "let", "var"]
}
],
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-unused-vars": "error"
},
"overrides": [
{
"files": ["*.spec.ts", "*.e2e-spec.ts"],
"rules": {
"@typescript-eslint/init-declarations": "off",
"max-lines-per-function": "off"
}
}
]
}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ lerna-debug.log*
*.launch
.settings/
*.sublime-workspace
.eslintcache

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/extensions.json
4 changes: 4 additions & 0 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run test
7 changes: 7 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
build
dist
coverage
e2e
node_modules
pnpm-lock.yaml
*.lock
8 changes: 4 additions & 4 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"arrowParens": "avoid",
"endOfLine": "auto",
"semi": true,
"tabWidth": 2,
"singleQuote": false,
"trailingComma": "all",
"arrowParens": "avoid",
"endOfLine": "auto"
"tabWidth": 2,
"trailingComma": "all"
}
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"format": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix && prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\"",
"test": "jest --verbose",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
Expand All @@ -28,8 +28,8 @@
"prepare": "husky install"
},
"lint-staged": {
"src/**/*.ts": "eslint --cache --fix",
"src/**/*.**": "prettier --check --ignore-unknown --write"
"src/**/*.ts": "eslint \"{src,apps,libs,test}/**/*.ts\" --cache",
"src/**/*.**": "prettier --check --ignore-unknown"
},
"dependencies": {
"@nestjs/common": "^9.0.0",
Expand All @@ -56,6 +56,7 @@
"@nestjs/cli": "^9.0.0",
"@nestjs/schematics": "^9.0.0",
"@nestjs/testing": "^9.0.0",
"@types/bcrypt": "^5.0.0",
"@types/express": "^4.17.13",
"@types/jest": "28.1.8",
"@types/node": "^16.0.0",
Expand All @@ -67,6 +68,7 @@
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-simple-import-sort": "^8.0.0",
"eslint-plugin-typescript-sort-keys": "^2.3.0",
"husky": "^8.0.2",
"jest": "28.1.3",
"lint-staged": "^13.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/app.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Test, TestingModule } from "@nestjs/testing";
import { type TestingModule, Test } from "@nestjs/testing";

import { AppController } from "./app.controller";
import { AppService } from "./app.service";
Expand Down
2 changes: 1 addition & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { validate } from "./config/env.validation";
import { UserModule } from "./user/user.module";

@Module({
controllers: [AppController],
imports: [
ConfigModule.forRoot({
validate,
Expand All @@ -18,7 +19,6 @@ import { UserModule } from "./user/user.module";
UserModule,
AuthModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
54 changes: 30 additions & 24 deletions src/auth/auth.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
import { ConflictException } from "@nestjs/common";
import { Test, TestingModule } from "@nestjs/testing";
import { type HttpException, ConflictException } from "@nestjs/common";
import { type TestingModule, Test } from "@nestjs/testing";
import { getRepositoryToken, TypeOrmModule } from "@nestjs/typeorm";
import { dataSourceJest } from "src/config/data-source";
import { UserEntity } from "src/user/entities/user.entity";
import { CreateUserRespose } from "src/user/resposes/create-user-respose";
import type { CreateUserRespose } from "src/user/resposes/create-user-respose";
import { UserService } from "src/user/user.service";
import { Repository } from "typeorm";
import type { Repository } from "typeorm";

import { CreateUserDto } from "../user/dto/create-user.dto";
import type { CreateUserDto } from "../user/dto/create-user.dto";
import { AuthController } from "./auth.controller";
import { AuthService } from "./auth.service";

describe("AuthController", () => {
let authController: AuthController;
let authService: AuthService;
let userRepository: Repository<UserEntity>;
let userRepository: Repository<UserEntity> | undefined;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [TypeOrmModule.forRoot(dataSourceJest)],
controllers: [AuthController],
imports: [TypeOrmModule.forRoot(dataSourceJest)],
providers: [
AuthService,
UserService,
{
provide: getRepositoryToken(UserEntity),
useValue: UserEntity, // 使用測試資料庫的 Repository
// 使用測試資料庫的 Repository
useValue: UserEntity,
},
],
}).compile();
Expand All @@ -35,45 +37,49 @@ describe("AuthController", () => {
getRepositoryToken(UserEntity),
);
});

describe("create", () => {
it("應該會創建一個使用者,並返回 201 狀態碼", async () => {
const createUserDto: CreateUserDto = {
account: "account",
email: "[email protected]",
name: "displayname",
account: "account",
password: "Password@123",
};
const expectedResponse: CreateUserRespose = {
statusCode: 201,
message: "創建成功",
statusCode: 201,
};

jest.spyOn(authService, "register").mockResolvedValue(expectedResponse);
const result = await authController.register(createUserDto);

expect(result).toEqual(expectedResponse);
});

it("應該會發生資料使用者重覆,並返回 409 狀態碼", async () => {
const createUserDto1: CreateUserDto = {
account: "account1",
email: "[email protected]",
name: "displayname",
account: "account1",
password: "Password@123",
};
try {
await authService.register(createUserDto1);
await authService.register(createUserDto1);
} catch (error) {
expect(error).toBeInstanceOf(ConflictException);
expect(error.response).toEqual({
statusCode: 409,
message: ["email 已被註冊。", "account 已被註冊。"],
error: "Conflict",

await authService.register(createUserDto1);
await authService
.register(createUserDto1)
.catch((error: HttpException) => {
expect(error).toBeInstanceOf(ConflictException);
expect(error.getResponse()).toEqual({
error: "Conflict",
message: ["email 已被註冊。", "account 已被註冊。"],
statusCode: 409,
});
});
}
});
});

afterEach(async () => {
if (userRepository && userRepository.clear) {
await userRepository.clear();
}
await userRepository?.clear();
});
});
5 changes: 3 additions & 2 deletions src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ import { AuthService } from "./auth.service";
@Controller("auth")
export class AuthController {
constructor(private readonly authService: AuthService) {}

@Post("register")
@ApiOperation({
summary: "使用者註冊",
description: "會檢查是否重複過的資料",
summary: "使用者註冊",
})
@ApiCreatedResponse({
description: "使用者創建成功",
Expand All @@ -34,7 +35,7 @@ export class AuthController {
description: "使用者格式不符",
type: CreateUserBadrequestError,
})
register(@Body() userDto: CreateUserDto) {
async register(@Body() userDto: CreateUserDto) {
return this.authService.register(userDto);
}
}
2 changes: 1 addition & 1 deletion src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { AuthController } from "./auth.controller";
import { AuthService } from "./auth.service";

@Module({
imports: [UserModule, TypeOrmModule.forFeature([UserEntity])],
controllers: [AuthController],
imports: [UserModule, TypeOrmModule.forFeature([UserEntity])],
providers: [AuthService],
})
export class AuthModule {}
Loading

0 comments on commit 2921cba

Please sign in to comment.