create-theta-code 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/create.js +9 -0
- package/package.json +34 -0
- package/src/cli.js +21 -0
- package/src/generators/scaffoldProject.js +46 -0
- package/src/prompts/getProjectName.js +30 -0
- package/src/prompts/getTemplateChoice.js +39 -0
- package/src/utils/logger.js +29 -0
- package/templates/mongo-js/.env +12 -0
- package/templates/mongo-js/.env.example +13 -0
- package/templates/mongo-js/.eslintrc.json +24 -0
- package/templates/mongo-js/.prettierrc +9 -0
- package/templates/mongo-js/README.md +429 -0
- package/templates/mongo-js/_env.example +13 -0
- package/templates/mongo-js/_gitignore +22 -0
- package/templates/mongo-js/package-lock.json +4671 -0
- package/templates/mongo-js/package.json +48 -0
- package/templates/mongo-js/server.js +67 -0
- package/templates/mongo-js/src/config/app.config.js +72 -0
- package/templates/mongo-js/src/config/db.config.js +32 -0
- package/templates/mongo-js/src/config/env.config.js +49 -0
- package/templates/mongo-js/src/config/rateLimiter.config.js +32 -0
- package/templates/mongo-js/src/middlewares/auth.middleware.js +20 -0
- package/templates/mongo-js/src/middlewares/error.middleware.js +61 -0
- package/templates/mongo-js/src/middlewares/notFound.middleware.js +11 -0
- package/templates/mongo-js/src/middlewares/requestId.middleware.js +10 -0
- package/templates/mongo-js/src/middlewares/requireRole.middleware.js +13 -0
- package/templates/mongo-js/src/middlewares/validate.middleware.js +21 -0
- package/templates/mongo-js/src/modules/user/user.controller.js +88 -0
- package/templates/mongo-js/src/modules/user/user.model.js +45 -0
- package/templates/mongo-js/src/modules/user/user.repository.js +47 -0
- package/templates/mongo-js/src/modules/user/user.routes.js +32 -0
- package/templates/mongo-js/src/modules/user/user.service.js +87 -0
- package/templates/mongo-js/src/modules/user/user.validator.js +28 -0
- package/templates/mongo-js/src/utils/AppError.js +15 -0
- package/templates/mongo-js/src/utils/apiResponse.js +23 -0
- package/templates/mongo-js/src/utils/asyncHandler.js +7 -0
- package/templates/mongo-js/src/utils/constants.js +16 -0
- package/templates/mongo-js/src/utils/jwt.utils.js +40 -0
- package/templates/mongo-js/tests/integration/user.routes.test.js +111 -0
- package/templates/mongo-js/tests/unit/user.service.test.js +96 -0
- package/templates/pg-js/.eslintrc.json +24 -0
- package/templates/pg-js/.prettierrc +9 -0
- package/templates/pg-js/_env.example +7 -0
- package/templates/pg-js/_gitignore +20 -0
- package/templates/pg-js/package.json +50 -0
- package/templates/pg-js/prisma/schema.prisma +23 -0
- package/templates/pg-js/server.js +63 -0
- package/templates/pg-js/src/config/app.config.js +48 -0
- package/templates/pg-js/src/config/db.config.js +30 -0
- package/templates/pg-js/src/config/env.config.js +36 -0
- package/templates/pg-js/src/config/rateLimiter.config.js +22 -0
- package/templates/pg-js/src/middlewares/auth.middleware.js +32 -0
- package/templates/pg-js/src/middlewares/error.middleware.js +50 -0
- package/templates/pg-js/src/middlewares/notFound.middleware.js +11 -0
- package/templates/pg-js/src/middlewares/validate.middleware.js +21 -0
- package/templates/pg-js/src/modules/user/user.controller.js +57 -0
- package/templates/pg-js/src/modules/user/user.model.js +20 -0
- package/templates/pg-js/src/modules/user/user.repository.js +105 -0
- package/templates/pg-js/src/modules/user/user.routes.js +27 -0
- package/templates/pg-js/src/modules/user/user.service.js +81 -0
- package/templates/pg-js/src/modules/user/user.validator.js +22 -0
- package/templates/pg-js/src/utils/AppError.js +14 -0
- package/templates/pg-js/src/utils/apiResponse.js +23 -0
- package/templates/pg-js/src/utils/asyncHandler.js +7 -0
- package/templates/pg-js/src/utils/constants.js +24 -0
- package/templates/pg-js/src/utils/jwt.utils.js +39 -0
- package/templates/pg-js/tests/integration/user.routes.test.js +95 -0
- package/templates/pg-js/tests/unit/user.service.test.js +96 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// tests/integration/user.routes.test.js — Integration tests for HTTP layer. Real app, mocked DB.
|
|
2
|
+
|
|
3
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
4
|
+
import request from 'supertest';
|
|
5
|
+
import { createApp } from '../../src/config/app.config.js';
|
|
6
|
+
import * as userRepository from '../../src/modules/user/user.repository.js';
|
|
7
|
+
|
|
8
|
+
vi.mock('../../src/modules/user/user.repository.js');
|
|
9
|
+
|
|
10
|
+
describe('User Routes', () => {
|
|
11
|
+
let app;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
app = createApp();
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('POST /api/v1/users/register', () => {
|
|
19
|
+
it('should register a new user', async () => {
|
|
20
|
+
vi.mocked(userRepository.findByEmailPublic).mockResolvedValueOnce(null);
|
|
21
|
+
vi.mocked(userRepository.create).mockResolvedValueOnce({
|
|
22
|
+
id: 1,
|
|
23
|
+
email: 'test@example.com',
|
|
24
|
+
firstName: 'John',
|
|
25
|
+
lastName: 'Doe',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const response = await request(app)
|
|
29
|
+
.post('/api/v1/users/register')
|
|
30
|
+
.send({
|
|
31
|
+
email: 'test@example.com',
|
|
32
|
+
firstName: 'John',
|
|
33
|
+
lastName: 'Doe',
|
|
34
|
+
password: 'Password123!',
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
expect(response.status).toBe(201);
|
|
38
|
+
expect(response.body).toHaveProperty('success', true);
|
|
39
|
+
expect(response.body).toHaveProperty('data.user');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should return 400 on validation error', async () => {
|
|
43
|
+
const response = await request(app)
|
|
44
|
+
.post('/api/v1/users/register')
|
|
45
|
+
.send({
|
|
46
|
+
email: 'invalid-email',
|
|
47
|
+
firstName: 'John',
|
|
48
|
+
lastName: 'Doe',
|
|
49
|
+
password: 'pass',
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(response.status).toBe(400);
|
|
53
|
+
expect(response.body).toHaveProperty('success', false);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('POST /api/v1/users/login', () => {
|
|
58
|
+
it('should login successfully', async () => {
|
|
59
|
+
const user = {
|
|
60
|
+
id: 1,
|
|
61
|
+
email: 'test@example.com',
|
|
62
|
+
password: '$2a$12$abcdefghijklmnopqrstuvwxyz',
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
vi.mocked(userRepository.findByEmail).mockResolvedValueOnce(user);
|
|
66
|
+
|
|
67
|
+
const response = await request(app)
|
|
68
|
+
.post('/api/v1/users/login')
|
|
69
|
+
.send({
|
|
70
|
+
email: 'test@example.com',
|
|
71
|
+
password: 'Password123!',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(response.status).toBeDefined();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('GET /health', () => {
|
|
79
|
+
it('should return health status', async () => {
|
|
80
|
+
const response = await request(app).get('/health');
|
|
81
|
+
|
|
82
|
+
expect(response.status).toBe(200);
|
|
83
|
+
expect(response.body).toHaveProperty('status', 'UP');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('404 handler', () => {
|
|
88
|
+
it('should return 404 for unknown routes', async () => {
|
|
89
|
+
const response = await request(app).get('/api/v1/unknown');
|
|
90
|
+
|
|
91
|
+
expect(response.status).toBe(404);
|
|
92
|
+
expect(response.body).toHaveProperty('success', false);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// tests/unit/user.service.test.js — Unit tests for business logic. Mocked repository.
|
|
2
|
+
|
|
3
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
4
|
+
import * as userService from '../../src/modules/user/user.service.js';
|
|
5
|
+
import * as userRepository from '../../src/modules/user/user.repository.js';
|
|
6
|
+
import { AppError } from '../../src/utils/AppError.js';
|
|
7
|
+
import bcryptjs from 'bcryptjs';
|
|
8
|
+
|
|
9
|
+
vi.mock('../../src/modules/user/user.repository.js');
|
|
10
|
+
vi.mock('bcryptjs');
|
|
11
|
+
|
|
12
|
+
describe('User Service', () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
vi.clearAllMocks();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('register', () => {
|
|
18
|
+
it('should create a new user successfully', async () => {
|
|
19
|
+
const userData = {
|
|
20
|
+
id: 1,
|
|
21
|
+
email: 'test@example.com',
|
|
22
|
+
firstName: 'John',
|
|
23
|
+
lastName: 'Doe',
|
|
24
|
+
password: 'hashedPassword123',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
vi.mocked(userRepository.findByEmailPublic).mockResolvedValueOnce(null);
|
|
28
|
+
vi.mocked(bcryptjs.hash).mockResolvedValueOnce('hashedPassword123');
|
|
29
|
+
vi.mocked(userRepository.create).mockResolvedValueOnce(userData);
|
|
30
|
+
|
|
31
|
+
const result = await userService.register(
|
|
32
|
+
'test@example.com',
|
|
33
|
+
'John',
|
|
34
|
+
'Doe',
|
|
35
|
+
'password123'
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect(result).toEqual(userData);
|
|
39
|
+
expect(userRepository.findByEmailPublic).toHaveBeenCalledWith('test@example.com');
|
|
40
|
+
expect(bcryptjs.hash).toHaveBeenCalledWith('password123', 12);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should throw error if email exists', async () => {
|
|
44
|
+
vi.mocked(userRepository.findByEmailPublic).mockResolvedValueOnce({ email: 'test@example.com' });
|
|
45
|
+
|
|
46
|
+
await expect(
|
|
47
|
+
userService.register('test@example.com', 'John', 'Doe', 'password123')
|
|
48
|
+
).rejects.toThrow(AppError);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('login', () => {
|
|
53
|
+
it('should return user and tokens on successful login', async () => {
|
|
54
|
+
const user = {
|
|
55
|
+
id: 1,
|
|
56
|
+
email: 'test@example.com',
|
|
57
|
+
password: 'hashedPassword123',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
vi.mocked(userRepository.findByEmail).mockResolvedValueOnce(user);
|
|
61
|
+
vi.mocked(bcryptjs.compare).mockResolvedValueOnce(true);
|
|
62
|
+
|
|
63
|
+
const result = await userService.login('test@example.com', 'password123');
|
|
64
|
+
|
|
65
|
+
expect(result).toHaveProperty('user');
|
|
66
|
+
expect(result).toHaveProperty('token');
|
|
67
|
+
expect(result).toHaveProperty('refreshToken');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should throw error on invalid credentials', async () => {
|
|
71
|
+
vi.mocked(userRepository.findByEmail).mockResolvedValueOnce(null);
|
|
72
|
+
|
|
73
|
+
await expect(
|
|
74
|
+
userService.login('test@example.com', 'password123')
|
|
75
|
+
).rejects.toThrow(AppError);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('getUserById', () => {
|
|
80
|
+
it('should return user by id', async () => {
|
|
81
|
+
const user = { id: 1, email: 'test@example.com' };
|
|
82
|
+
vi.mocked(userRepository.findById).mockResolvedValueOnce(user);
|
|
83
|
+
|
|
84
|
+
const result = await userService.getUserById(1);
|
|
85
|
+
|
|
86
|
+
expect(result).toEqual(user);
|
|
87
|
+
expect(userRepository.findById).toHaveBeenCalledWith(1);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should throw error if user not found', async () => {
|
|
91
|
+
vi.mocked(userRepository.findById).mockResolvedValueOnce(null);
|
|
92
|
+
|
|
93
|
+
await expect(userService.getUserById(1)).rejects.toThrow(AppError);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
});
|