imlil 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/.eslintrc.cjs +40 -0
- package/DOCS.md +63 -0
- package/README.md +160 -0
- package/agentTestSandbox/cli-test-zone/README.md +0 -0
- package/agentTestSandbox/cli-test-zone/imlil.blueprint.json +5 -0
- package/agentTestSandbox/cli-test-zone/notes-warning.md +3 -0
- package/agentTestSandbox/cli-test-zone/package.json +0 -0
- package/agentTestSandbox/cli-test-zone/public/index.html +0 -0
- package/agentTestSandbox/cli-test-zone/src/App.js +0 -0
- package/agentTestSandbox/cli-test-zone/src/App.jsx +29 -0
- package/agentTestSandbox/cli-test-zone/src/__tests__/App.test.jsx +48 -0
- package/agentTestSandbox/cli-test-zone/src/components/AddTodo.js +0 -0
- package/agentTestSandbox/cli-test-zone/src/components/Navigation/Navigation.jsx +48 -0
- package/agentTestSandbox/cli-test-zone/src/components/Navigation/__tests__/Navigation.module.test.js +45 -0
- package/agentTestSandbox/cli-test-zone/src/components/Navigation/__tests__/Navigation.test.jsx +47 -0
- package/agentTestSandbox/cli-test-zone/src/components/Navigation.js +0 -0
- package/agentTestSandbox/cli-test-zone/src/components/TodoItem/TodoItem.jsx +41 -0
- package/agentTestSandbox/cli-test-zone/src/components/TodoItem/__tests__/TodoItem.test.jsx +65 -0
- package/agentTestSandbox/cli-test-zone/src/components/TodoItem.js +0 -0
- package/agentTestSandbox/cli-test-zone/src/components/TodoList/TodoList.module.css +62 -0
- package/agentTestSandbox/cli-test-zone/src/components/TodoList.js +0 -0
- package/agentTestSandbox/cli-test-zone/src/index.js +0 -0
- package/agentTestSandbox/cli-test-zone/src/pages/About.js +0 -0
- package/agentTestSandbox/cli-test-zone/src/pages/Home.js +0 -0
- package/agentTestSandbox/cli-test-zone/src/store/TodoContext.js +0 -0
- package/agentTestSandbox/cli-test-zone/src/styles/Todo.css +0 -0
- package/agentTestSandbox/cli-test-zone/src/styles/index.css +0 -0
- package/agentTestSandbox/cli-test-zone/src/utils/__tests__/localStorage.test.js +48 -0
- package/agentTestSandbox/cli-test-zone/src/utils/localStorage.js +38 -0
- package/agentTestSandbox/parallel-test/.env.example +0 -0
- package/agentTestSandbox/parallel-test/.eslintrc.json +0 -0
- package/agentTestSandbox/parallel-test/.github/workflows/__tests__/workflows.test.ts +115 -0
- package/agentTestSandbox/parallel-test/.github/workflows/cd.yml +0 -0
- package/agentTestSandbox/parallel-test/.github/workflows/ci.yml +4 -0
- package/agentTestSandbox/parallel-test/.imlil/plan-2026-02-08.md +186 -0
- package/agentTestSandbox/parallel-test/.prettierrc +0 -0
- package/agentTestSandbox/parallel-test/Dockerfile +0 -0
- package/agentTestSandbox/parallel-test/README.md +3 -0
- package/agentTestSandbox/parallel-test/ast.json +74 -0
- package/agentTestSandbox/parallel-test/docker-compose.yml +4 -0
- package/agentTestSandbox/parallel-test/jest.config.js +61 -0
- package/agentTestSandbox/parallel-test/k8s/__tests__/deployment.test.ts +168 -0
- package/agentTestSandbox/parallel-test/k8s/frontend-deployment.yaml +4 -0
- package/agentTestSandbox/parallel-test/nginx/nginx.conf +0 -0
- package/agentTestSandbox/parallel-test/package.json +50 -0
- package/agentTestSandbox/parallel-test/prisma/__tests__/schema.test.ts +176 -0
- package/agentTestSandbox/parallel-test/prisma/schema.prisma +109 -0
- package/agentTestSandbox/parallel-test/server/__tests__/controllers/dashboard.controller.test.ts +127 -0
- package/agentTestSandbox/parallel-test/server/__tests__/index.test.ts +60 -0
- package/agentTestSandbox/parallel-test/server/__tests__/models/user.model.test.ts +111 -0
- package/agentTestSandbox/parallel-test/server/config/__tests__/swagger.test.ts +128 -0
- package/agentTestSandbox/parallel-test/server/config/database.ts +0 -0
- package/agentTestSandbox/parallel-test/server/config/redis.ts +0 -0
- package/agentTestSandbox/parallel-test/server/config/swagger.ts +0 -0
- package/agentTestSandbox/parallel-test/server/controllers/__tests__/auth.controller.test.ts +178 -0
- package/agentTestSandbox/parallel-test/server/controllers/__tests__/user.controller.test.ts +105 -0
- package/agentTestSandbox/parallel-test/server/controllers/auth.controller.ts +148 -0
- package/agentTestSandbox/parallel-test/server/controllers/dashboard.controller.ts +137 -0
- package/agentTestSandbox/parallel-test/server/controllers/user.controller.ts +161 -0
- package/agentTestSandbox/parallel-test/server/index.ts +62 -0
- package/agentTestSandbox/parallel-test/server/middleware/__tests__/auth.middleware.test.ts +74 -0
- package/agentTestSandbox/parallel-test/server/middleware/auth.middleware.ts +55 -0
- package/agentTestSandbox/parallel-test/server/middleware/error.middleware.ts +0 -0
- package/agentTestSandbox/parallel-test/server/middleware/validation.middleware.ts +0 -0
- package/agentTestSandbox/parallel-test/server/models/analytics.model.ts +0 -0
- package/agentTestSandbox/parallel-test/server/models/profile.model.ts +0 -0
- package/agentTestSandbox/parallel-test/server/models/user.model.ts +78 -0
- package/agentTestSandbox/parallel-test/server/routes/auth.routes.ts +0 -0
- package/agentTestSandbox/parallel-test/server/routes/dashboard.routes.ts +0 -0
- package/agentTestSandbox/parallel-test/server/routes/user.routes.ts +0 -0
- package/agentTestSandbox/parallel-test/src/App.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/__tests__/config.test.ts +127 -0
- package/agentTestSandbox/parallel-test/src/__tests__/index.test.tsx +36 -0
- package/agentTestSandbox/parallel-test/src/__tests__/setup.test.ts +34 -0
- package/agentTestSandbox/parallel-test/src/__tests__/setupTest.test.ts +44 -0
- package/agentTestSandbox/parallel-test/src/components/common/Button/Button.tsx +80 -0
- package/agentTestSandbox/parallel-test/src/components/common/Button/__tests__/Button.test.tsx +75 -0
- package/agentTestSandbox/parallel-test/src/components/common/Card/Card.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/components/common/Input/Input.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/components/common/Table/Table.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/components/features/Authentication/LoginForm.tsx +75 -0
- package/agentTestSandbox/parallel-test/src/components/features/Authentication/RegisterForm.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/components/features/Authentication/__tests__/LoginForm.test.tsx +101 -0
- package/agentTestSandbox/parallel-test/src/components/features/Dashboard/AnalyticsChart.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/components/features/Dashboard/DashboardStats.tsx +81 -0
- package/agentTestSandbox/parallel-test/src/components/features/Dashboard/__tests__/DashboardStats.test.tsx +122 -0
- package/agentTestSandbox/parallel-test/src/components/layouts/Header.tsx +70 -0
- package/agentTestSandbox/parallel-test/src/components/layouts/MainLayout.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/components/layouts/Sidebar.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/components/layouts/__tests__/MainLayout.test.tsx +65 -0
- package/agentTestSandbox/parallel-test/src/hooks/__tests__/useAuth.test.ts +75 -0
- package/agentTestSandbox/parallel-test/src/hooks/useApi.ts +0 -0
- package/agentTestSandbox/parallel-test/src/hooks/useAuth.ts +54 -0
- package/agentTestSandbox/parallel-test/src/hooks/useTheme.ts +0 -0
- package/agentTestSandbox/parallel-test/src/index.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/services/__tests__/api.service.test.ts +48 -0
- package/agentTestSandbox/parallel-test/src/services/analytics.service.ts +0 -0
- package/agentTestSandbox/parallel-test/src/services/api.service.ts +59 -0
- package/agentTestSandbox/parallel-test/src/services/api.ts +0 -0
- package/agentTestSandbox/parallel-test/src/services/auth.service.ts +0 -0
- package/agentTestSandbox/parallel-test/src/services/user.service.ts +0 -0
- package/agentTestSandbox/parallel-test/src/store/__tests__/store.test.ts +60 -0
- package/agentTestSandbox/parallel-test/src/store/index.ts +23 -0
- package/agentTestSandbox/parallel-test/src/store/slices/authSlice.ts +0 -0
- package/agentTestSandbox/parallel-test/src/store/slices/dashboardSlice.ts +0 -0
- package/agentTestSandbox/parallel-test/src/store/slices/userSlice.ts +0 -0
- package/agentTestSandbox/parallel-test/src/types/auth.types.ts +0 -0
- package/agentTestSandbox/parallel-test/src/types/dashboard.types.ts +0 -0
- package/agentTestSandbox/parallel-test/src/types/user.types.ts +0 -0
- package/agentTestSandbox/parallel-test/src/utils/constants.ts +0 -0
- package/agentTestSandbox/parallel-test/src/utils/formatters.ts +0 -0
- package/agentTestSandbox/parallel-test/src/utils/validation.ts +0 -0
- package/agentTestSandbox/parallel-test/src/views/Dashboard.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/views/Login.tsx +31 -0
- package/agentTestSandbox/parallel-test/src/views/Profile.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/views/Register.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/views/Settings.tsx +0 -0
- package/agentTestSandbox/parallel-test/src/views/__tests__/Login.test.tsx +62 -0
- package/agentTestSandbox/parallel-test/src/vite-env.d.ts +1 -0
- package/agentTestSandbox/parallel-test/tailwind.config.js +0 -0
- package/agentTestSandbox/parallel-test/tests/integration/api/auth.test.ts +120 -0
- package/agentTestSandbox/parallel-test/tests/unit/components/Button.test.tsx +35 -0
- package/agentTestSandbox/parallel-test/tests/unit/config/jest.config.test.js +62 -0
- package/agentTestSandbox/parallel-test/tests/unit/config/jest.setup.test.js +52 -0
- package/agentTestSandbox/parallel-test/tests/unit/infrastructure/__tests__/docker-config.test.ts +107 -0
- package/agentTestSandbox/parallel-test/tsconfig.json +0 -0
- package/agentTestSandbox/zone2/Makefile +58 -0
- package/agentTestSandbox/zone2/README.md +0 -0
- package/agentTestSandbox/zone2/docs/API.md +0 -0
- package/agentTestSandbox/zone2/docs/CONTRIBUTING.md +0 -0
- package/agentTestSandbox/zone2/imlil.blueprint.json +5 -0
- package/agentTestSandbox/zone2/notes-warning.md +3 -0
- package/agentTestSandbox/zone2/src/calculator.c +0 -0
- package/agentTestSandbox/zone2/src/calculator.h +0 -0
- package/agentTestSandbox/zone2/src/core/__tests__/test_memory.c +89 -0
- package/agentTestSandbox/zone2/src/core/memory.c +60 -0
- package/agentTestSandbox/zone2/src/display.c +0 -0
- package/agentTestSandbox/zone2/src/display.h +0 -0
- package/agentTestSandbox/zone2/src/input_handler.c +0 -0
- package/agentTestSandbox/zone2/src/input_handler.h +0 -0
- package/agentTestSandbox/zone2/src/main.c +0 -0
- package/agentTestSandbox/zone2/src/utils/error_handling.c +0 -0
- package/agentTestSandbox/zone2/src/utils/error_handling.h +0 -0
- package/agentTestSandbox/zone2/src/utils/input.c +0 -0
- package/agentTestSandbox/zone2/src/utils/input.h +0 -0
- package/agentTestSandbox/zone2/src/utils/math_utils.c +0 -0
- package/agentTestSandbox/zone2/src/utils/math_utils.h +0 -0
- package/agentTestSandbox/zone2/src/utils/stack.c +0 -0
- package/agentTestSandbox/zone2/src/utils/stack.h +0 -0
- package/agentTestSandbox/zone2/src/utils.c +34 -0
- package/agentTestSandbox/zone2/tests/__tests__/test_makefile.c +58 -0
- package/agentTestSandbox/zone2/tests/calculator_tests.c +0 -0
- package/agentTestSandbox/zone2/tests/input_handler_tests.c +0 -0
- package/agentTestSandbox/zone2/tests/math_utils_tests.c +0 -0
- package/agentTestSandbox/zone2/tests/test_calculator.c +0 -0
- package/agentTestSandbox/zone2/tests/test_input.c +0 -0
- package/agentTestSandbox/zone2/tests/test_stack.c +0 -0
- package/agentTestSandbox/zone2/tests/test_utils.c +8 -0
- package/bin/cli.js +369 -0
- package/imlil.config.js +22 -0
- package/index.js +0 -0
- package/jest.config.js +5 -0
- package/package.json +45 -0
- package/src/__tests__/cli.test.js +5 -0
- package/src/actions/Action.js +125 -0
- package/src/agents/Agent.js +64 -0
- package/src/agents/Operator.js +147 -0
- package/src/agents/ScrumAgent.js +74 -0
- package/src/agents/SupervisorAgent.js +198 -0
- package/src/agents/ValidatorAgent.js +48 -0
- package/src/agents/coder.js +208 -0
- package/src/agents/worker.js +52 -0
- package/src/utils/db.js +40 -0
- package/src/utils/embedapi.js +19 -0
- package/test-api.js +24 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
|
|
5
|
+
describe('Kubernetes Deployment Configuration Tests', () => {
|
|
6
|
+
const k8sPath = path.resolve(__dirname, '..');
|
|
7
|
+
|
|
8
|
+
// Test deployment files existence
|
|
9
|
+
test('should have required k8s deployment files', () => {
|
|
10
|
+
const requiredFiles = [
|
|
11
|
+
'deployment.yaml',
|
|
12
|
+
'service.yaml',
|
|
13
|
+
'ingress.yaml',
|
|
14
|
+
'configmap.yaml',
|
|
15
|
+
'secrets.yaml'
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
requiredFiles.forEach(file => {
|
|
19
|
+
expect(fs.existsSync(path.join(k8sPath, file))).toBeTruthy();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Test deployment.yaml configuration
|
|
24
|
+
describe('deployment.yaml', () => {
|
|
25
|
+
let deploymentConfig;
|
|
26
|
+
|
|
27
|
+
beforeAll(() => {
|
|
28
|
+
const deploymentFile = fs.readFileSync(
|
|
29
|
+
path.join(k8sPath, 'deployment.yaml'),
|
|
30
|
+
'utf8'
|
|
31
|
+
);
|
|
32
|
+
deploymentConfig = yaml.load(deploymentFile);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('should have correct API version and kind', () => {
|
|
36
|
+
expect(deploymentConfig.apiVersion).toBe('apps/v1');
|
|
37
|
+
expect(deploymentConfig.kind).toBe('Deployment');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('should have proper metadata', () => {
|
|
41
|
+
expect(deploymentConfig.metadata).toHaveProperty('name');
|
|
42
|
+
expect(deploymentConfig.metadata).toHaveProperty('namespace');
|
|
43
|
+
expect(deploymentConfig.metadata.labels).toBeDefined();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('should have correct deployment spec', () => {
|
|
47
|
+
expect(deploymentConfig.spec).toHaveProperty('replicas');
|
|
48
|
+
expect(deploymentConfig.spec).toHaveProperty('selector');
|
|
49
|
+
expect(deploymentConfig.spec).toHaveProperty('template');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('should have container specifications', () => {
|
|
53
|
+
const containers = deploymentConfig.spec.template.spec.containers;
|
|
54
|
+
expect(containers).toBeInstanceOf(Array);
|
|
55
|
+
expect(containers.length).toBeGreaterThan(0);
|
|
56
|
+
|
|
57
|
+
const mainContainer = containers[0];
|
|
58
|
+
expect(mainContainer).toHaveProperty('name');
|
|
59
|
+
expect(mainContainer).toHaveProperty('image');
|
|
60
|
+
expect(mainContainer).toHaveProperty('ports');
|
|
61
|
+
expect(mainContainer).toHaveProperty('resources');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('should have resource limits and requests', () => {
|
|
65
|
+
const container = deploymentConfig.spec.template.spec.containers[0];
|
|
66
|
+
expect(container.resources).toHaveProperty('limits');
|
|
67
|
+
expect(container.resources).toHaveProperty('requests');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Test service.yaml configuration
|
|
72
|
+
describe('service.yaml', () => {
|
|
73
|
+
let serviceConfig;
|
|
74
|
+
|
|
75
|
+
beforeAll(() => {
|
|
76
|
+
const serviceFile = fs.readFileSync(
|
|
77
|
+
path.join(k8sPath, 'service.yaml'),
|
|
78
|
+
'utf8'
|
|
79
|
+
);
|
|
80
|
+
serviceConfig = yaml.load(serviceFile);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('should have correct API version and kind', () => {
|
|
84
|
+
expect(serviceConfig.apiVersion).toBe('v1');
|
|
85
|
+
expect(serviceConfig.kind).toBe('Service');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('should have proper service specifications', () => {
|
|
89
|
+
expect(serviceConfig.spec).toHaveProperty('selector');
|
|
90
|
+
expect(serviceConfig.spec).toHaveProperty('ports');
|
|
91
|
+
expect(serviceConfig.spec.ports).toBeInstanceOf(Array);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Test ingress.yaml configuration
|
|
96
|
+
describe('ingress.yaml', () => {
|
|
97
|
+
let ingressConfig;
|
|
98
|
+
|
|
99
|
+
beforeAll(() => {
|
|
100
|
+
const ingressFile = fs.readFileSync(
|
|
101
|
+
path.join(k8sPath, 'ingress.yaml'),
|
|
102
|
+
'utf8'
|
|
103
|
+
);
|
|
104
|
+
ingressConfig = yaml.load(ingressFile);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('should have correct API version and kind', () => {
|
|
108
|
+
expect(ingressConfig.apiVersion).toBe('networking.k8s.io/v1');
|
|
109
|
+
expect(ingressConfig.kind).toBe('Ingress');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('should have proper ingress rules', () => {
|
|
113
|
+
expect(ingressConfig.spec).toHaveProperty('rules');
|
|
114
|
+
expect(ingressConfig.spec.rules).toBeInstanceOf(Array);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Test configmap.yaml configuration
|
|
119
|
+
describe('configmap.yaml', () => {
|
|
120
|
+
let configMapConfig;
|
|
121
|
+
|
|
122
|
+
beforeAll(() => {
|
|
123
|
+
const configMapFile = fs.readFileSync(
|
|
124
|
+
path.join(k8sPath, 'configmap.yaml'),
|
|
125
|
+
'utf8'
|
|
126
|
+
);
|
|
127
|
+
configMapConfig = yaml.load(configMapFile);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('should have correct API version and kind', () => {
|
|
131
|
+
expect(configMapConfig.apiVersion).toBe('v1');
|
|
132
|
+
expect(configMapConfig.kind).toBe('ConfigMap');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('should have data section', () => {
|
|
136
|
+
expect(configMapConfig).toHaveProperty('data');
|
|
137
|
+
expect(typeof configMapConfig.data).toBe('object');
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Test secrets.yaml configuration
|
|
142
|
+
describe('secrets.yaml', () => {
|
|
143
|
+
let secretsConfig;
|
|
144
|
+
|
|
145
|
+
beforeAll(() => {
|
|
146
|
+
const secretsFile = fs.readFileSync(
|
|
147
|
+
path.join(k8sPath, 'secrets.yaml'),
|
|
148
|
+
'utf8'
|
|
149
|
+
);
|
|
150
|
+
secretsConfig = yaml.load(secretsFile);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('should have correct API version and kind', () => {
|
|
154
|
+
expect(secretsConfig.apiVersion).toBe('v1');
|
|
155
|
+
expect(secretsConfig.kind).toBe('Secret');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('should have proper secret type', () => {
|
|
159
|
+
expect(secretsConfig).toHaveProperty('type');
|
|
160
|
+
expect(secretsConfig.type).toBe('Opaque');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test('should have data section', () => {
|
|
164
|
+
expect(secretsConfig).toHaveProperty('data');
|
|
165
|
+
expect(typeof secretsConfig.data).toBe('object');
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
});
|
|
File without changes
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "admin-dashboard",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "tsc && vite build",
|
|
8
|
+
"preview": "vite preview",
|
|
9
|
+
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
|
10
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
|
|
11
|
+
"test": "jest",
|
|
12
|
+
"test:watch": "jest --watch",
|
|
13
|
+
"test:coverage": "jest --coverage"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@emotion/react": "^11.11.1",
|
|
17
|
+
"@emotion/styled": "^11.11.0",
|
|
18
|
+
"@mui/material": "^5.14.5",
|
|
19
|
+
"@reduxjs/toolkit": "^1.9.5",
|
|
20
|
+
"axios": "^1.4.0",
|
|
21
|
+
"react": "^18.2.0",
|
|
22
|
+
"react-dom": "^18.2.0",
|
|
23
|
+
"react-hook-form": "^7.45.4",
|
|
24
|
+
"react-redux": "^8.1.2",
|
|
25
|
+
"react-router-dom": "^6.15.0",
|
|
26
|
+
"recharts": "^2.7.3",
|
|
27
|
+
"yup": "^1.2.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@testing-library/jest-dom": "^6.1.2",
|
|
31
|
+
"@testing-library/react": "^14.0.0",
|
|
32
|
+
"@types/node": "^20.5.7",
|
|
33
|
+
"@types/react": "^18.2.21",
|
|
34
|
+
"@types/react-dom": "^18.2.7",
|
|
35
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
36
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
37
|
+
"@vitejs/plugin-react": "^4.0.3",
|
|
38
|
+
"autoprefixer": "^10.4.15",
|
|
39
|
+
"eslint": "^8.45.0",
|
|
40
|
+
"eslint-config-airbnb": "^19.0.4",
|
|
41
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
42
|
+
"eslint-plugin-react-refresh": "^0.4.3",
|
|
43
|
+
"jest": "^29.6.4",
|
|
44
|
+
"postcss": "^8.4.28",
|
|
45
|
+
"prettier": "^3.0.2",
|
|
46
|
+
"tailwindcss": "^3.3.3",
|
|
47
|
+
"typescript": "^5.0.2",
|
|
48
|
+
"vite": "^4.4.5"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { PrismaClient } from '@prisma/client';
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
describe('Prisma Schema Validation', () => {
|
|
6
|
+
let prisma: PrismaClient;
|
|
7
|
+
|
|
8
|
+
beforeAll(async () => {
|
|
9
|
+
// Reset the database before running tests
|
|
10
|
+
execSync('npx prisma migrate reset --force');
|
|
11
|
+
prisma = new PrismaClient();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterAll(async () => {
|
|
15
|
+
await prisma.$disconnect();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('User Model', () => {
|
|
19
|
+
it('should create a user with required fields', async () => {
|
|
20
|
+
const user = await prisma.user.create({
|
|
21
|
+
data: {
|
|
22
|
+
email: 'test@example.com',
|
|
23
|
+
password: 'hashedPassword123',
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
expect(user).toHaveProperty('id');
|
|
28
|
+
expect(user.email).toBe('test@example.com');
|
|
29
|
+
expect(user.createdAt).toBeInstanceOf(Date);
|
|
30
|
+
expect(user.updatedAt).toBeInstanceOf(Date);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should not allow duplicate emails', async () => {
|
|
34
|
+
await expect(
|
|
35
|
+
prisma.user.create({
|
|
36
|
+
data: {
|
|
37
|
+
email: 'test@example.com',
|
|
38
|
+
password: 'anotherPassword',
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
).rejects.toThrow();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('Profile Model', () => {
|
|
46
|
+
let userId: string;
|
|
47
|
+
|
|
48
|
+
beforeAll(async () => {
|
|
49
|
+
const user = await prisma.user.create({
|
|
50
|
+
data: {
|
|
51
|
+
email: 'profile.test@example.com',
|
|
52
|
+
password: 'hashedPassword123',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
userId = user.id;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should create a profile linked to a user', async () => {
|
|
59
|
+
const profile = await prisma.profile.create({
|
|
60
|
+
data: {
|
|
61
|
+
firstName: 'John',
|
|
62
|
+
lastName: 'Doe',
|
|
63
|
+
userId: userId,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(profile).toHaveProperty('id');
|
|
68
|
+
expect(profile.firstName).toBe('John');
|
|
69
|
+
expect(profile.lastName).toBe('Doe');
|
|
70
|
+
expect(profile.userId).toBe(userId);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should not allow multiple profiles for the same user', async () => {
|
|
74
|
+
await expect(
|
|
75
|
+
prisma.profile.create({
|
|
76
|
+
data: {
|
|
77
|
+
firstName: 'Jane',
|
|
78
|
+
lastName: 'Doe',
|
|
79
|
+
userId: userId,
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
).rejects.toThrow();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('Analytics Model', () => {
|
|
87
|
+
let userId: string;
|
|
88
|
+
|
|
89
|
+
beforeAll(async () => {
|
|
90
|
+
const user = await prisma.user.create({
|
|
91
|
+
data: {
|
|
92
|
+
email: 'analytics.test@example.com',
|
|
93
|
+
password: 'hashedPassword123',
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
userId = user.id;
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should create analytics entry for a user', async () => {
|
|
100
|
+
const analytics = await prisma.analytics.create({
|
|
101
|
+
data: {
|
|
102
|
+
userId: userId,
|
|
103
|
+
eventType: 'LOGIN',
|
|
104
|
+
eventData: { ip: '127.0.0.1', userAgent: 'Test Browser' },
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
expect(analytics).toHaveProperty('id');
|
|
109
|
+
expect(analytics.userId).toBe(userId);
|
|
110
|
+
expect(analytics.eventType).toBe('LOGIN');
|
|
111
|
+
expect(analytics.eventData).toEqual({
|
|
112
|
+
ip: '127.0.0.1',
|
|
113
|
+
userAgent: 'Test Browser',
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should allow multiple analytics entries for the same user', async () => {
|
|
118
|
+
await prisma.analytics.createMany({
|
|
119
|
+
data: [
|
|
120
|
+
{
|
|
121
|
+
userId: userId,
|
|
122
|
+
eventType: 'PAGE_VIEW',
|
|
123
|
+
eventData: { page: '/dashboard' },
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
userId: userId,
|
|
127
|
+
eventType: 'PAGE_VIEW',
|
|
128
|
+
eventData: { page: '/profile' },
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const analyticsCount = await prisma.analytics.count({
|
|
134
|
+
where: { userId: userId },
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
expect(analyticsCount).toBeGreaterThanOrEqual(3);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('Model Relationships', () => {
|
|
142
|
+
it('should fetch user with related profile and analytics', async () => {
|
|
143
|
+
const testUser = await prisma.user.create({
|
|
144
|
+
data: {
|
|
145
|
+
email: 'relationships.test@example.com',
|
|
146
|
+
password: 'hashedPassword123',
|
|
147
|
+
profile: {
|
|
148
|
+
create: {
|
|
149
|
+
firstName: 'Test',
|
|
150
|
+
lastName: 'User',
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
analytics: {
|
|
154
|
+
create: {
|
|
155
|
+
eventType: 'REGISTRATION',
|
|
156
|
+
eventData: { source: 'direct' },
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const userWithRelations = await prisma.user.findUnique({
|
|
163
|
+
where: { id: testUser.id },
|
|
164
|
+
include: {
|
|
165
|
+
profile: true,
|
|
166
|
+
analytics: true,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
expect(userWithRelations).toHaveProperty('profile');
|
|
171
|
+
expect(userWithRelations?.profile?.firstName).toBe('Test');
|
|
172
|
+
expect(userWithRelations?.analytics).toHaveLength(1);
|
|
173
|
+
expect(userWithRelations?.analytics[0].eventType).toBe('REGISTRATION');
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// This is your Prisma schema file,
|
|
2
|
+
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
3
|
+
|
|
4
|
+
generator client {
|
|
5
|
+
provider = "prisma-client-js"
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
datasource db {
|
|
9
|
+
provider = "postgresql"
|
|
10
|
+
url = env("DATABASE_URL")
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// User model - Core user information
|
|
14
|
+
model User {
|
|
15
|
+
id String @id @default(cuid())
|
|
16
|
+
email String @unique
|
|
17
|
+
passwordHash String
|
|
18
|
+
role Role @default(USER)
|
|
19
|
+
status UserStatus @default(ACTIVE)
|
|
20
|
+
createdAt DateTime @default(now())
|
|
21
|
+
updatedAt DateTime @updatedAt
|
|
22
|
+
lastLoginAt DateTime?
|
|
23
|
+
|
|
24
|
+
// Relations
|
|
25
|
+
profile Profile?
|
|
26
|
+
analytics Analytics[]
|
|
27
|
+
|
|
28
|
+
// Security and account management
|
|
29
|
+
resetToken String?
|
|
30
|
+
resetTokenExpiry DateTime?
|
|
31
|
+
verificationToken String?
|
|
32
|
+
isVerified Boolean @default(false)
|
|
33
|
+
|
|
34
|
+
@@map("users")
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Profile model - Extended user information
|
|
38
|
+
model Profile {
|
|
39
|
+
id String @id @default(cuid())
|
|
40
|
+
userId String @unique
|
|
41
|
+
firstName String?
|
|
42
|
+
lastName String?
|
|
43
|
+
avatar String?
|
|
44
|
+
phoneNumber String?
|
|
45
|
+
timezone String @default("UTC")
|
|
46
|
+
language String @default("en")
|
|
47
|
+
|
|
48
|
+
// Preferences and settings
|
|
49
|
+
notifications NotificationSettings?
|
|
50
|
+
theme String @default("light")
|
|
51
|
+
|
|
52
|
+
// Metadata
|
|
53
|
+
createdAt DateTime @default(now())
|
|
54
|
+
updatedAt DateTime @updatedAt
|
|
55
|
+
|
|
56
|
+
// Relations
|
|
57
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
58
|
+
|
|
59
|
+
@@map("profiles")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Analytics model - User activity and metrics
|
|
63
|
+
model Analytics {
|
|
64
|
+
id String @id @default(cuid())
|
|
65
|
+
userId String
|
|
66
|
+
eventType String
|
|
67
|
+
eventData Json
|
|
68
|
+
userAgent String?
|
|
69
|
+
ipAddress String?
|
|
70
|
+
timestamp DateTime @default(now())
|
|
71
|
+
|
|
72
|
+
// Relations
|
|
73
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
74
|
+
|
|
75
|
+
// Indexes for better query performance
|
|
76
|
+
@@index([userId, eventType])
|
|
77
|
+
@@index([timestamp])
|
|
78
|
+
|
|
79
|
+
@@map("analytics")
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Notification settings - Embedded in Profile
|
|
83
|
+
model NotificationSettings {
|
|
84
|
+
id String @id @default(cuid())
|
|
85
|
+
profileId String @unique
|
|
86
|
+
email Boolean @default(true)
|
|
87
|
+
push Boolean @default(true)
|
|
88
|
+
sms Boolean @default(false)
|
|
89
|
+
marketing Boolean @default(false)
|
|
90
|
+
|
|
91
|
+
// Relations
|
|
92
|
+
profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade)
|
|
93
|
+
|
|
94
|
+
@@map("notification_settings")
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Enums
|
|
98
|
+
enum Role {
|
|
99
|
+
ADMIN
|
|
100
|
+
MANAGER
|
|
101
|
+
USER
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
enum UserStatus {
|
|
105
|
+
ACTIVE
|
|
106
|
+
INACTIVE
|
|
107
|
+
SUSPENDED
|
|
108
|
+
PENDING
|
|
109
|
+
}
|
package/agentTestSandbox/parallel-test/server/__tests__/controllers/dashboard.controller.test.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
import { DashboardController } from '../../controllers/dashboard.controller';
|
|
3
|
+
import prisma from '../../config/database';
|
|
4
|
+
|
|
5
|
+
// Mock the Prisma client
|
|
6
|
+
jest.mock('../../config/database', () => ({
|
|
7
|
+
analytics: {
|
|
8
|
+
findMany: jest.fn(),
|
|
9
|
+
groupBy: jest.fn(),
|
|
10
|
+
aggregate: jest.fn(),
|
|
11
|
+
},
|
|
12
|
+
user: {
|
|
13
|
+
count: jest.fn(),
|
|
14
|
+
},
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
describe('DashboardController', () => {
|
|
18
|
+
let mockRequest: Partial<Request>;
|
|
19
|
+
let mockResponse: Partial<Response>;
|
|
20
|
+
let dashboardController: DashboardController;
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
mockRequest = {
|
|
24
|
+
query: {},
|
|
25
|
+
params: {},
|
|
26
|
+
body: {},
|
|
27
|
+
};
|
|
28
|
+
mockResponse = {
|
|
29
|
+
status: jest.fn().mockReturnThis(),
|
|
30
|
+
json: jest.fn(),
|
|
31
|
+
};
|
|
32
|
+
dashboardController = new DashboardController();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('getDashboardStats', () => {
|
|
36
|
+
it('should return dashboard statistics successfully', async () => {
|
|
37
|
+
// Mock the prisma queries
|
|
38
|
+
const mockUserCount = 100;
|
|
39
|
+
const mockAnalytics = [
|
|
40
|
+
{ id: 1, value: 150, timestamp: new Date() },
|
|
41
|
+
{ id: 2, value: 200, timestamp: new Date() },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
(prisma.user.count as jest.Mock).mockResolvedValue(mockUserCount);
|
|
45
|
+
(prisma.analytics.findMany as jest.Mock).mockResolvedValue(mockAnalytics);
|
|
46
|
+
|
|
47
|
+
await dashboardController.getDashboardStats(
|
|
48
|
+
mockRequest as Request,
|
|
49
|
+
mockResponse as Response
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
expect(mockResponse.status).toHaveBeenCalledWith(200);
|
|
53
|
+
expect(mockResponse.json).toHaveBeenCalledWith({
|
|
54
|
+
success: true,
|
|
55
|
+
data: {
|
|
56
|
+
totalUsers: mockUserCount,
|
|
57
|
+
analytics: mockAnalytics,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should handle errors appropriately', async () => {
|
|
63
|
+
const errorMessage = 'Database error';
|
|
64
|
+
(prisma.user.count as jest.Mock).mockRejectedValue(new Error(errorMessage));
|
|
65
|
+
|
|
66
|
+
await dashboardController.getDashboardStats(
|
|
67
|
+
mockRequest as Request,
|
|
68
|
+
mockResponse as Response
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
expect(mockResponse.status).toHaveBeenCalledWith(500);
|
|
72
|
+
expect(mockResponse.json).toHaveBeenCalledWith({
|
|
73
|
+
success: false,
|
|
74
|
+
error: 'Failed to fetch dashboard statistics',
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('getAnalytics', () => {
|
|
80
|
+
it('should return analytics data with proper date filtering', async () => {
|
|
81
|
+
const mockRequest = {
|
|
82
|
+
query: {
|
|
83
|
+
startDate: '2026-01-01',
|
|
84
|
+
endDate: '2026-02-08',
|
|
85
|
+
},
|
|
86
|
+
} as Partial<Request>;
|
|
87
|
+
|
|
88
|
+
const mockAnalyticsData = [
|
|
89
|
+
{ date: '2026-01-01', count: 10 },
|
|
90
|
+
{ date: '2026-01-02', count: 15 },
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
(prisma.analytics.groupBy as jest.Mock).mockResolvedValue(mockAnalyticsData);
|
|
94
|
+
|
|
95
|
+
await dashboardController.getAnalytics(
|
|
96
|
+
mockRequest as Request,
|
|
97
|
+
mockResponse as Response
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect(mockResponse.status).toHaveBeenCalledWith(200);
|
|
101
|
+
expect(mockResponse.json).toHaveBeenCalledWith({
|
|
102
|
+
success: true,
|
|
103
|
+
data: mockAnalyticsData,
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should handle invalid date parameters', async () => {
|
|
108
|
+
const mockRequest = {
|
|
109
|
+
query: {
|
|
110
|
+
startDate: 'invalid-date',
|
|
111
|
+
endDate: '2026-02-08',
|
|
112
|
+
},
|
|
113
|
+
} as Partial<Request>;
|
|
114
|
+
|
|
115
|
+
await dashboardController.getAnalytics(
|
|
116
|
+
mockRequest as Request,
|
|
117
|
+
mockResponse as Response
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
expect(mockResponse.status).toHaveBeenCalledWith(400);
|
|
121
|
+
expect(mockResponse.json).toHaveBeenCalledWith({
|
|
122
|
+
success: false,
|
|
123
|
+
error: 'Invalid date parameters',
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import request from 'supertest';
|
|
2
|
+
import { Express } from 'express';
|
|
3
|
+
import { createServer } from '../index';
|
|
4
|
+
import { connectDatabase } from '../config/database';
|
|
5
|
+
import { connectRedis } from '../config/redis';
|
|
6
|
+
|
|
7
|
+
// Mock the database and redis connections
|
|
8
|
+
jest.mock('../config/database');
|
|
9
|
+
jest.mock('../config/redis');
|
|
10
|
+
|
|
11
|
+
describe('Server Setup', () => {
|
|
12
|
+
let app: Express;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
// Reset all mocks before each test
|
|
16
|
+
jest.clearAllMocks();
|
|
17
|
+
app = await createServer();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('Server Initialization', () => {
|
|
21
|
+
it('should create an Express server successfully', async () => {
|
|
22
|
+
expect(app).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should connect to database on startup', async () => {
|
|
26
|
+
expect(connectDatabase).toHaveBeenCalled();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should connect to Redis on startup', async () => {
|
|
30
|
+
expect(connectRedis).toHaveBeenCalled();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should respond to health check endpoint', async () => {
|
|
34
|
+
const response = await request(app).get('/health');
|
|
35
|
+
expect(response.status).toBe(200);
|
|
36
|
+
expect(response.body).toEqual({ status: 'ok' });
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should handle undefined routes', async () => {
|
|
40
|
+
const response = await request(app).get('/non-existent-route');
|
|
41
|
+
expect(response.status).toBe(404);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('Server Configuration', () => {
|
|
46
|
+
it('should use JSON middleware', async () => {
|
|
47
|
+
const response = await request(app)
|
|
48
|
+
.post('/api/test')
|
|
49
|
+
.send({ test: 'data' });
|
|
50
|
+
|
|
51
|
+
// Even though route doesn't exist, server should parse JSON
|
|
52
|
+
expect(response.status).toBe(404);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should have CORS enabled', async () => {
|
|
56
|
+
const response = await request(app).options('/');
|
|
57
|
+
expect(response.headers['access-control-allow-origin']).toBeDefined();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|