refactor: cập nhật cấu hình ESLint, TypeScript để bao gồm tệp kiểm thử và chuẩn hóa cách sắp xếp import, ghi log.

This commit is contained in:
Ho Ngoc Hai
2026-01-07 18:15:00 +07:00
parent eca4b84249
commit a7d2362b2f
17 changed files with 76 additions and 51 deletions

View File

@@ -3,12 +3,26 @@
import goodgoConfig from '@goodgo/eslint-config'; import goodgoConfig from '@goodgo/eslint-config';
export default [ export default [
...goodgoConfig, // EN: Global ignores (must be first and standalone)
// VI: Ignores toàn cục (phải đặt đầu tiên và độc lập)
{ {
// EN: Service-specific overrides (exclude test files) ignores: [
// VI: Override riêng cho service (loại trừ test files) '**/*.test.ts',
files: ['**/*.ts'], '**/*.spec.ts',
ignores: ['**/*.test.ts', '**/*.spec.ts', '**/__tests__/**'], '**/*.e2e.ts',
'**/__tests__/**',
'**/tests/**',
'dist/**',
'node_modules/**',
],
},
// EN: Apply base config
// VI: Áp dụng config cơ bản
...goodgoConfig,
// EN: Service-specific configuration
// VI: Cấu hình riêng cho service
{
files: ['src/**/*.ts'],
languageOptions: { languageOptions: {
parserOptions: { parserOptions: {
tsconfigRootDir: import.meta.dirname, tsconfigRootDir: import.meta.dirname,

View File

@@ -1,9 +0,0 @@
module.exports = {
ignorePatterns: ['.eslintrc.js'],
extends: ['@goodgo/eslint-config'],
root: true,
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json',
},
};

View File

@@ -3,12 +3,26 @@
import goodgoConfig from '@goodgo/eslint-config'; import goodgoConfig from '@goodgo/eslint-config';
export default [ export default [
...goodgoConfig, // EN: Global ignores (must be first and standalone)
// VI: Ignores toàn cục (phải đặt đầu tiên và độc lập)
{ {
// EN: Service-specific overrides (exclude test files) ignores: [
// VI: Override riêng cho service (loại trừ test files) '**/*.test.ts',
files: ['**/*.ts'], '**/*.spec.ts',
ignores: ['**/*.test.ts', '**/*.spec.ts', '**/__tests__/**'], '**/*.e2e.ts',
'**/__tests__/**',
'**/tests/**',
'dist/**',
'node_modules/**',
],
},
// EN: Apply base config
// VI: Áp dụng config cơ bản
...goodgoConfig,
// EN: Service-specific configuration
// VI: Cấu hình riêng cho service
{
files: ['src/**/*.ts'],
languageOptions: { languageOptions: {
parserOptions: { parserOptions: {
tsconfigRootDir: import.meta.dirname, tsconfigRootDir: import.meta.dirname,

View File

@@ -1,8 +1,8 @@
import express from 'express'; import express from 'express';
import request from 'supertest'; import request from 'supertest';
import { createRouter } from '../routes';
import { getPrismaClient } from '../config/database.config'; import { getPrismaClient } from '../config/database.config';
import { createRouter } from '../routes';
// EN: Mock getPrismaClient to return the mocked prisma client // EN: Mock getPrismaClient to return the mocked prisma client
// VI: Mock getPrismaClient để trả về mocked prisma client // VI: Mock getPrismaClient để trả về mocked prisma client

View File

@@ -1,8 +1,8 @@
import express from 'express'; import express from 'express';
import request from 'supertest'; import request from 'supertest';
import { createRouter } from '../routes';
import { getPrismaClient } from '../config/database.config'; import { getPrismaClient } from '../config/database.config';
import { createRouter } from '../routes';
// EN: Mock getPrismaClient to return a mock prisma client // EN: Mock getPrismaClient to return a mock prisma client
// VI: Mock getPrismaClient để trả về mock prisma client // VI: Mock getPrismaClient để trả về mock prisma client

View File

@@ -1,6 +1,6 @@
import { PrismaClient } from '@prisma/client';
import { execSync } from 'child_process'; import { execSync } from 'child_process';
import { join } from 'path';
import { PrismaClient } from '@prisma/client';
// Test database configuration // Test database configuration
export const TEST_DATABASE_URL = process.env.TEST_DATABASE_URL || 'postgresql://test:test@localhost:5433/test_iam_db'; export const TEST_DATABASE_URL = process.env.TEST_DATABASE_URL || 'postgresql://test:test@localhost:5433/test_iam_db';
@@ -14,7 +14,7 @@ let prisma: PrismaClient;
*/ */
export async function setupTestDatabase() { export async function setupTestDatabase() {
try { try {
console.log('🚀 Setting up test database...'); console.warn('🚀 Setting up test database...');
// Create test database if it doesn't exist // Create test database if it doesn't exist
try { try {
@@ -22,10 +22,10 @@ export async function setupTestDatabase() {
stdio: 'pipe', stdio: 'pipe',
env: { ...process.env, PGPASSWORD: 'test' } env: { ...process.env, PGPASSWORD: 'test' }
}); });
console.log('✅ Test database created'); console.warn('✅ Test database created');
} catch (error) { } catch {
// Database might already exist, continue // Database might already exist, continue
console.log(' Test database already exists'); console.warn(' Test database already exists');
} }
// Initialize Prisma client with test database // Initialize Prisma client with test database
@@ -35,23 +35,23 @@ export async function setupTestDatabase() {
// Connect to database // Connect to database
await prisma.$connect(); await prisma.$connect();
console.log('✅ Connected to test database'); console.warn('✅ Connected to test database');
// Run migrations // Run migrations
console.log('📦 Running database migrations...'); console.warn('📦 Running database migrations...');
execSync('cd services/iam-service && pnpm prisma:migrate:deploy', { execSync('cd services/iam-service && pnpm prisma:migrate:deploy', {
stdio: 'inherit', stdio: 'inherit',
env: { ...process.env, DATABASE_URL: TEST_DATABASE_URL } env: { ...process.env, DATABASE_URL: TEST_DATABASE_URL }
}); });
console.log('✅ Migrations completed'); console.warn('✅ Migrations completed');
// Seed test data // Seed test data
console.log('🌱 Seeding test data...'); console.warn('🌱 Seeding test data...');
execSync('cd services/iam-service && pnpm prisma:db:seed', { execSync('cd services/iam-service && pnpm prisma:db:seed', {
stdio: 'inherit', stdio: 'inherit',
env: { ...process.env, DATABASE_URL: TEST_DATABASE_URL } env: { ...process.env, DATABASE_URL: TEST_DATABASE_URL }
}); });
console.log('✅ Test data seeded'); console.warn('✅ Test data seeded');
return prisma; return prisma;
} catch (error) { } catch (error) {
@@ -65,7 +65,7 @@ export async function setupTestDatabase() {
*/ */
export async function teardownTestDatabase() { export async function teardownTestDatabase() {
try { try {
console.log('🧹 Cleaning up test database...'); console.warn('🧹 Cleaning up test database...');
if (prisma) { if (prisma) {
// Clear all data // Clear all data
@@ -93,7 +93,7 @@ export async function teardownTestDatabase() {
]); ]);
await prisma.$disconnect(); await prisma.$disconnect();
console.log('✅ Test database cleaned and disconnected'); console.warn('✅ Test database cleaned and disconnected');
} }
} catch (error) { } catch (error) {
console.error('❌ Failed to cleanup test database:', error); console.error('❌ Failed to cleanup test database:', error);

View File

@@ -1,4 +1,3 @@
import { logger } from '@goodgo/logger';
import { initTracing } from '@goodgo/tracing'; import { initTracing } from '@goodgo/tracing';
import cookieParser from 'cookie-parser'; import cookieParser from 'cookie-parser';
import cors from 'cors'; import cors from 'cors';

View File

@@ -1,3 +1,4 @@
import { logger } from '@goodgo/logger';
import { Application } from 'express'; import { Application } from 'express';
import swaggerJSDoc from 'swagger-jsdoc'; import swaggerJSDoc from 'swagger-jsdoc';
import swaggerUi from 'swagger-ui-express'; import swaggerUi from 'swagger-ui-express';
@@ -605,7 +606,7 @@ export const setupSwagger = (app: Application, basePath: string = '/api-docs') =
res.send(JSON.stringify(specs, null, 2)); res.send(JSON.stringify(specs, null, 2));
}); });
console.log(`📚 Swagger documentation available at: http://localhost:${appConfig.port}${basePath}`); logger.info(`📚 Swagger documentation available at: http://localhost:${appConfig.port}${basePath}`);
}; };
export { specs }; export { specs };

View File

@@ -1,6 +1,7 @@
import request from 'supertest';
import { app } from '../../../app';
import { PrismaClient } from '@prisma/client'; import { PrismaClient } from '@prisma/client';
import request from 'supertest';
import { app } from '../../../app';
const prisma = new PrismaClient(); const prisma = new PrismaClient();

View File

@@ -1,6 +1,6 @@
import { TestFactory } from '../../../__tests__/factories';
import { AuthController } from '../auth.controller'; import { AuthController } from '../auth.controller';
import { authService } from '../auth.service'; import { authService } from '../auth.service';
import { TestFactory } from '../../../__tests__/factories';
// Mock dependencies // Mock dependencies
jest.mock('../auth.service'); jest.mock('../auth.service');

View File

@@ -1,12 +1,14 @@
import { AuthService } from '../auth.service'; import bcrypt from 'bcryptjs';
import { TestFactory } from '../../../__tests__/factories';
import { prisma } from '../../../config/database.config'; import { prisma } from '../../../config/database.config';
import { auditService } from '../../../core/events/audit.service';
import { rbacService } from '../../rbac/rbac.service'; import { rbacService } from '../../rbac/rbac.service';
import { sessionService } from '../../session/session.service'; import { sessionService } from '../../session/session.service';
import { jwtService } from '../../token/jwt.service'; import { jwtService } from '../../token/jwt.service';
import { auditService } from '../../../core/events/audit.service';
import { accountLockoutService } from '../account-lockout.service'; import { accountLockoutService } from '../account-lockout.service';
import { TestFactory } from '../../../__tests__/factories'; import { AuthService } from '../auth.service';
import bcrypt from 'bcryptjs';
// Mock dependencies // Mock dependencies
jest.mock('../../rbac/rbac.service'); jest.mock('../../rbac/rbac.service');

View File

@@ -1,6 +1,6 @@
import { prisma } from '../../../config/database.config';
import { ConflictError } from '../../../errors/http-error'; import { ConflictError } from '../../../errors/http-error';
import { FeatureRepository } from '../feature.repository'; import { FeatureRepository } from '../feature.repository';
import { prisma } from '../../../config/database.config';
// EN: Use jest.mocked to properly type the mock // EN: Use jest.mocked to properly type the mock
// VI: Sử dụng jest.mocked để type mock đúng cách // VI: Sử dụng jest.mocked để type mock đúng cách

View File

@@ -39,7 +39,7 @@ export class HealthController {
data: { status: 'ready' }, data: { status: 'ready' },
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}); });
} catch (error) { } catch {
// EN: Return 503 if database is not ready // EN: Return 503 if database is not ready
// VI: Trả về 503 nếu database chưa sẵn sàng // VI: Trả về 503 nếu database chưa sẵn sàng
res.status(503).json({ res.status(503).json({

View File

@@ -1,8 +1,8 @@
import { PrismaClient } from '@prisma/client'; import { PrismaClient } from '@prisma/client';
import { RBACService } from '../rbac.service';
import { RoleRepository, PermissionRepository } from '../../../repositories/role.repository'; import { RoleRepository, PermissionRepository } from '../../../repositories/role.repository';
import { UserRepository } from '../../../repositories/user.repository'; import { UserRepository } from '../../../repositories/user.repository';
import { RBACService } from '../rbac.service';
// Mock dependencies // Mock dependencies
jest.mock('../../../config/database.config'); jest.mock('../../../config/database.config');

View File

@@ -40,6 +40,7 @@ describe('UserRepository', () => {
const result = await repository.findByEmail(email); const result = await repository.findByEmail(email);
expect(result).toEqual(mockUser);
expect(mockPrisma.user.findUnique).toHaveBeenCalledWith({ expect(mockPrisma.user.findUnique).toHaveBeenCalledWith({
where: { email }, where: { email },
include: { include: {
@@ -68,6 +69,7 @@ describe('UserRepository', () => {
const result = await repository.findByUsername(username); const result = await repository.findByUsername(username);
expect(result).toEqual(mockUser);
expect(mockPrisma.user.findUnique).toHaveBeenCalledWith({ expect(mockPrisma.user.findUnique).toHaveBeenCalledWith({
where: { username }, where: { username },
}); });
@@ -88,6 +90,7 @@ describe('UserRepository', () => {
const result = await repository.findWithPermissions(userId); const result = await repository.findWithPermissions(userId);
expect(result).toEqual(mockUser);
expect(mockPrisma.user.findUnique).toHaveBeenCalledWith({ expect(mockPrisma.user.findUnique).toHaveBeenCalledWith({
where: { id: userId }, where: { id: userId },
include: expect.objectContaining({ include: expect.objectContaining({

View File

@@ -1,4 +1,5 @@
import { Request } from 'express'; import { Request } from 'express';
import { import {
generateRandomString, generateRandomString,
hashString, hashString,

View File

@@ -17,13 +17,12 @@
"noUnusedParameters": false "noUnusedParameters": false
}, },
"include": [ "include": [
"src/**/*" "src/**/*",
"src/**/*.test.ts",
"src/__tests__/**/*"
], ],
"exclude": [ "exclude": [
"node_modules", "node_modules",
"dist", "dist"
"tests",
"src/__tests__",
"**/*.test.ts"
] ]
} }