Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci/enhance lint rules #8

Merged
merged 5 commits into from
Jun 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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