@slingr/cli 0.0.3 → 0.0.4

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.
Files changed (251) hide show
  1. package/LICENSE.txt +202 -0
  2. package/README.md +490 -319
  3. package/bin/dev.cmd +2 -2
  4. package/bin/dev.js +5 -5
  5. package/bin/run.cmd +2 -2
  6. package/bin/run.js +4 -4
  7. package/bin/slingr +1 -0
  8. package/dist/commands/build.d.ts +20 -0
  9. package/dist/commands/build.d.ts.map +1 -0
  10. package/dist/commands/build.js +206 -0
  11. package/dist/commands/build.js.map +1 -0
  12. package/dist/commands/create-app.d.ts +0 -1
  13. package/dist/commands/create-app.d.ts.map +1 -1
  14. package/dist/commands/create-app.js +38 -57
  15. package/dist/commands/create-app.js.map +1 -1
  16. package/dist/commands/debug.d.ts +28 -0
  17. package/dist/commands/debug.d.ts.map +1 -0
  18. package/dist/commands/debug.js +474 -0
  19. package/dist/commands/debug.js.map +1 -0
  20. package/dist/commands/ds.d.ts +14 -1
  21. package/dist/commands/ds.d.ts.map +1 -1
  22. package/dist/commands/ds.js +450 -121
  23. package/dist/commands/ds.js.map +1 -1
  24. package/dist/commands/gql.d.ts +1 -1
  25. package/dist/commands/gql.d.ts.map +1 -1
  26. package/dist/commands/gql.js +190 -184
  27. package/dist/commands/gql.js.map +1 -1
  28. package/dist/commands/infra/down.d.ts.map +1 -1
  29. package/dist/commands/infra/down.js +8 -7
  30. package/dist/commands/infra/down.js.map +1 -1
  31. package/dist/commands/infra/up.d.ts.map +1 -1
  32. package/dist/commands/infra/up.js +8 -7
  33. package/dist/commands/infra/up.js.map +1 -1
  34. package/dist/commands/infra/update.d.ts +1 -0
  35. package/dist/commands/infra/update.d.ts.map +1 -1
  36. package/dist/commands/infra/update.js +33 -69
  37. package/dist/commands/infra/update.js.map +1 -1
  38. package/dist/commands/run.d.ts +29 -2
  39. package/dist/commands/run.d.ts.map +1 -1
  40. package/dist/commands/run.js +628 -130
  41. package/dist/commands/run.js.map +1 -1
  42. package/dist/commands/setup.d.ts +1 -1
  43. package/dist/commands/setup.d.ts.map +1 -1
  44. package/dist/commands/setup.js +34 -71
  45. package/dist/commands/setup.js.map +1 -1
  46. package/dist/commands/sync-metadata.d.ts +15 -0
  47. package/dist/commands/sync-metadata.d.ts.map +1 -0
  48. package/dist/commands/sync-metadata.js +225 -0
  49. package/dist/commands/sync-metadata.js.map +1 -0
  50. package/dist/commands/users.d.ts +30 -0
  51. package/dist/commands/users.d.ts.map +1 -0
  52. package/dist/commands/users.js +472 -0
  53. package/dist/commands/users.js.map +1 -0
  54. package/dist/commands/views.d.ts +11 -0
  55. package/dist/commands/views.d.ts.map +1 -0
  56. package/dist/commands/views.js +73 -0
  57. package/dist/commands/views.js.map +1 -0
  58. package/dist/projectStructure.d.ts +2 -2
  59. package/dist/projectStructure.d.ts.map +1 -1
  60. package/dist/projectStructure.js +281 -69
  61. package/dist/projectStructure.js.map +1 -1
  62. package/dist/scripts/generate-metadata.d.ts +13 -0
  63. package/dist/scripts/generate-metadata.d.ts.map +1 -0
  64. package/dist/scripts/generate-metadata.js +412 -0
  65. package/dist/scripts/generate-metadata.js.map +1 -0
  66. package/dist/scripts/generate-metadata.ts +498 -0
  67. package/dist/scripts/generate-schema.d.ts +1 -1
  68. package/dist/scripts/generate-schema.js +168 -74
  69. package/dist/scripts/generate-schema.js.map +1 -1
  70. package/dist/scripts/generate-schema.ts +258 -143
  71. package/dist/templates/.env.template +23 -0
  72. package/dist/templates/.firebaserc.template +5 -0
  73. package/dist/templates/.github/copilot-instructions.md.template +652 -17
  74. package/dist/templates/backend/Dockerfile.template +30 -0
  75. package/dist/templates/config/datasource.ts.template +12 -9
  76. package/dist/templates/config/jest.config.ts +30 -30
  77. package/dist/templates/config/jest.setup.ts +1 -1
  78. package/dist/templates/config/tsconfig.json.template +50 -29
  79. package/dist/templates/dataSources/mysql.ts.template +16 -13
  80. package/dist/templates/dataSources/postgres.ts.template +15 -13
  81. package/dist/templates/dataset-generator-script.ts.template +139 -139
  82. package/dist/templates/datasets/mysql-default/.slingr-schema.json.template +5 -0
  83. package/dist/templates/datasets/mysql-default/Address.jsonl.template +3 -3
  84. package/dist/templates/datasets/mysql-default/App.jsonl.template +4 -4
  85. package/dist/templates/datasets/mysql-default/Company.jsonl.template +3 -3
  86. package/dist/templates/datasets/mysql-default/Person.jsonl.template +2 -2
  87. package/dist/templates/datasets/mysql-default/User.jsonl.template +1 -0
  88. package/dist/templates/datasets/mysql-default/instructions.md.template +1 -0
  89. package/dist/templates/datasets/postgres-default/.slingr-schema.json.template +5 -0
  90. package/dist/templates/datasets/postgres-default/Address.jsonl.template +3 -3
  91. package/dist/templates/datasets/postgres-default/App.jsonl.template +4 -4
  92. package/dist/templates/datasets/postgres-default/Company.jsonl.template +3 -3
  93. package/dist/templates/datasets/postgres-default/Person.jsonl.template +2 -2
  94. package/dist/templates/datasets/postgres-default/User.jsonl.template +1 -0
  95. package/dist/templates/datasets/postgres-default/instructions.md.template +1 -0
  96. package/dist/templates/docker-compose.prod-test.yml.template +32 -0
  97. package/dist/templates/docker-compose.yml.template +24 -0
  98. package/dist/templates/docs/app-description.md.template +33 -33
  99. package/dist/templates/firebase.json.template +68 -0
  100. package/dist/templates/frontend/.umirc.ts.template +23 -0
  101. package/dist/templates/frontend/package.json.template +45 -0
  102. package/dist/templates/frontend/public/config.json +6 -0
  103. package/dist/templates/frontend/public/logo.svg +6 -0
  104. package/dist/templates/frontend/src/app.tsx.template +44 -0
  105. package/dist/templates/frontend/src/global.less.template +117 -0
  106. package/dist/templates/frontend/src/layouts/MainLayout.tsx.template +75 -0
  107. package/dist/templates/frontend/src/types/graphql-augmentation.d.ts.template +44 -0
  108. package/dist/templates/frontend/src/views/customViews/user/UserCreateView.tsx.template +18 -0
  109. package/dist/templates/frontend/src/views/customViews/user/UserEditView.tsx.template +29 -0
  110. package/dist/templates/frontend/src/views/customViews/user/UserReadView.tsx.template +24 -0
  111. package/dist/templates/frontend/src/views/customViews/user/UserTableView.tsx.template +38 -0
  112. package/dist/templates/frontend/src/views/customViews/welcome.tsx.template +34 -0
  113. package/dist/templates/frontend/tsconfig.json.template +50 -0
  114. package/dist/templates/gql/codegen.yml.template +25 -25
  115. package/dist/templates/gql/index.ts.template +17 -24
  116. package/dist/templates/gql/operations.graphql.template +30 -30
  117. package/dist/templates/ops/README.md.template +1045 -0
  118. package/dist/templates/ops/cloudbuild.yaml.template +161 -0
  119. package/dist/templates/ops/scripts/_utils.js.template +217 -0
  120. package/dist/templates/ops/scripts/deploy.js.template +145 -0
  121. package/dist/templates/ops/scripts/setup-gcp.js.template +330 -0
  122. package/dist/templates/ops/scripts/setup-secrets.js.template +76 -0
  123. package/dist/templates/ops/scripts/test-prod-local.js.template +49 -0
  124. package/dist/templates/package.json.template +50 -38
  125. package/dist/templates/pnpm-workspace.yaml.template +3 -0
  126. package/dist/templates/prompt-analysis.md.template +110 -110
  127. package/dist/templates/prompt-script-generation.md.template +258 -258
  128. package/dist/templates/src/Address.ts.template +28 -31
  129. package/dist/templates/src/App.ts.template +17 -61
  130. package/dist/templates/src/Company.ts.template +41 -47
  131. package/dist/templates/src/Models.test.ts.template +654 -654
  132. package/dist/templates/src/Person.test.ts.template +289 -289
  133. package/dist/templates/src/Person.ts.template +90 -105
  134. package/dist/templates/src/actions/index.ts.template +11 -11
  135. package/dist/templates/src/auth/permissions.ts.template +34 -0
  136. package/dist/templates/src/data/App.ts.template +48 -0
  137. package/dist/templates/src/data/User.ts.template +35 -0
  138. package/dist/templates/src/types/gql.d.ts.template +17 -17
  139. package/dist/templates/vscode/extensions.json +4 -3
  140. package/dist/templates/vscode/settings.json +17 -11
  141. package/dist/templates/workspace-package.json.template +21 -0
  142. package/dist/utils/buildCache.d.ts +12 -0
  143. package/dist/utils/buildCache.d.ts.map +1 -0
  144. package/dist/utils/buildCache.js +102 -0
  145. package/dist/utils/buildCache.js.map +1 -0
  146. package/dist/utils/checkFramework.d.ts +27 -0
  147. package/dist/utils/checkFramework.d.ts.map +1 -0
  148. package/dist/utils/checkFramework.js +104 -0
  149. package/dist/utils/checkFramework.js.map +1 -0
  150. package/dist/utils/datasourceParser.d.ts +11 -0
  151. package/dist/utils/datasourceParser.d.ts.map +1 -1
  152. package/dist/utils/datasourceParser.js +154 -56
  153. package/dist/utils/datasourceParser.js.map +1 -1
  154. package/dist/utils/dockerManager.d.ts +25 -0
  155. package/dist/utils/dockerManager.d.ts.map +1 -0
  156. package/dist/utils/dockerManager.js +281 -0
  157. package/dist/utils/dockerManager.js.map +1 -0
  158. package/dist/utils/infraFileParser.d.ts +26 -0
  159. package/dist/utils/infraFileParser.d.ts.map +1 -0
  160. package/dist/utils/infraFileParser.js +75 -0
  161. package/dist/utils/infraFileParser.js.map +1 -0
  162. package/dist/utils/jsonlLoader.d.ts +91 -12
  163. package/dist/utils/jsonlLoader.d.ts.map +1 -1
  164. package/dist/utils/jsonlLoader.js +674 -63
  165. package/dist/utils/jsonlLoader.js.map +1 -1
  166. package/dist/utils/model-analyzer.d.ts.map +1 -1
  167. package/dist/utils/model-analyzer.js +67 -13
  168. package/dist/utils/model-analyzer.js.map +1 -1
  169. package/dist/utils/userManagement.d.ts +57 -0
  170. package/dist/utils/userManagement.d.ts.map +1 -0
  171. package/dist/utils/userManagement.js +288 -0
  172. package/dist/utils/userManagement.js.map +1 -0
  173. package/dist/utils/viewsGenerator.d.ts +15 -0
  174. package/dist/utils/viewsGenerator.d.ts.map +1 -0
  175. package/dist/utils/viewsGenerator.js +311 -0
  176. package/dist/utils/viewsGenerator.js.map +1 -0
  177. package/oclif.manifest.json +445 -20
  178. package/package.json +29 -26
  179. package/src/templates/.env.template +23 -0
  180. package/src/templates/.firebaserc.template +5 -0
  181. package/src/templates/.github/copilot-instructions.md.template +652 -17
  182. package/src/templates/backend/Dockerfile.template +30 -0
  183. package/src/templates/config/datasource.ts.template +12 -9
  184. package/src/templates/config/jest.config.ts +30 -30
  185. package/src/templates/config/jest.setup.ts +1 -1
  186. package/src/templates/config/tsconfig.json.template +50 -29
  187. package/src/templates/dataSources/mysql.ts.template +16 -13
  188. package/src/templates/dataSources/postgres.ts.template +15 -13
  189. package/src/templates/dataset-generator-script.ts.template +139 -139
  190. package/src/templates/datasets/mysql-default/.slingr-schema.json.template +5 -0
  191. package/src/templates/datasets/mysql-default/Address.jsonl.template +3 -3
  192. package/src/templates/datasets/mysql-default/App.jsonl.template +4 -4
  193. package/src/templates/datasets/mysql-default/Company.jsonl.template +3 -3
  194. package/src/templates/datasets/mysql-default/Person.jsonl.template +2 -2
  195. package/src/templates/datasets/mysql-default/User.jsonl.template +1 -0
  196. package/src/templates/datasets/mysql-default/instructions.md.template +1 -0
  197. package/src/templates/datasets/postgres-default/.slingr-schema.json.template +5 -0
  198. package/src/templates/datasets/postgres-default/Address.jsonl.template +3 -3
  199. package/src/templates/datasets/postgres-default/App.jsonl.template +4 -4
  200. package/src/templates/datasets/postgres-default/Company.jsonl.template +3 -3
  201. package/src/templates/datasets/postgres-default/Person.jsonl.template +2 -2
  202. package/src/templates/datasets/postgres-default/User.jsonl.template +1 -0
  203. package/src/templates/datasets/postgres-default/instructions.md.template +1 -0
  204. package/src/templates/docker-compose.prod-test.yml.template +32 -0
  205. package/src/templates/docker-compose.yml.template +24 -0
  206. package/src/templates/docs/app-description.md.template +33 -33
  207. package/src/templates/firebase.json.template +68 -0
  208. package/src/templates/frontend/.umirc.ts.template +23 -0
  209. package/src/templates/frontend/package.json.template +45 -0
  210. package/src/templates/frontend/public/config.json +6 -0
  211. package/src/templates/frontend/public/logo.svg +6 -0
  212. package/src/templates/frontend/src/app.tsx.template +44 -0
  213. package/src/templates/frontend/src/global.less.template +117 -0
  214. package/src/templates/frontend/src/layouts/MainLayout.tsx.template +75 -0
  215. package/src/templates/frontend/src/types/graphql-augmentation.d.ts.template +44 -0
  216. package/src/templates/frontend/src/views/customViews/user/UserCreateView.tsx.template +18 -0
  217. package/src/templates/frontend/src/views/customViews/user/UserEditView.tsx.template +29 -0
  218. package/src/templates/frontend/src/views/customViews/user/UserReadView.tsx.template +24 -0
  219. package/src/templates/frontend/src/views/customViews/user/UserTableView.tsx.template +38 -0
  220. package/src/templates/frontend/src/views/customViews/welcome.tsx.template +34 -0
  221. package/src/templates/frontend/tsconfig.json.template +50 -0
  222. package/src/templates/gql/codegen.yml.template +25 -25
  223. package/src/templates/gql/index.ts.template +17 -24
  224. package/src/templates/gql/operations.graphql.template +30 -30
  225. package/src/templates/ops/README.md.template +1045 -0
  226. package/src/templates/ops/cloudbuild.yaml.template +161 -0
  227. package/src/templates/ops/scripts/_utils.js.template +217 -0
  228. package/src/templates/ops/scripts/deploy.js.template +145 -0
  229. package/src/templates/ops/scripts/setup-gcp.js.template +330 -0
  230. package/src/templates/ops/scripts/setup-secrets.js.template +76 -0
  231. package/src/templates/ops/scripts/test-prod-local.js.template +49 -0
  232. package/src/templates/package.json.template +50 -38
  233. package/src/templates/pnpm-workspace.yaml.template +3 -0
  234. package/src/templates/prompt-analysis.md.template +110 -110
  235. package/src/templates/prompt-script-generation.md.template +258 -258
  236. package/src/templates/src/Address.ts.template +28 -31
  237. package/src/templates/src/App.ts.template +17 -61
  238. package/src/templates/src/Company.ts.template +41 -47
  239. package/src/templates/src/Models.test.ts.template +654 -654
  240. package/src/templates/src/Person.test.ts.template +289 -289
  241. package/src/templates/src/Person.ts.template +90 -105
  242. package/src/templates/src/actions/index.ts.template +11 -11
  243. package/src/templates/src/auth/permissions.ts.template +34 -0
  244. package/src/templates/src/data/App.ts.template +48 -0
  245. package/src/templates/src/data/User.ts.template +35 -0
  246. package/src/templates/src/types/gql.d.ts.template +17 -17
  247. package/src/templates/vscode/extensions.json +4 -3
  248. package/src/templates/vscode/settings.json +17 -11
  249. package/src/templates/workspace-package.json.template +21 -0
  250. package/dist/templates/src/index.ts +0 -66
  251. package/src/templates/src/index.ts +0 -66
@@ -1,289 +1,289 @@
1
- import { Person } from './Person';
2
-
3
- describe('Person Model', () => {
4
- describe('Validation Tests', () => {
5
- it('should validate a valid adult person', async () => {
6
- const personData = {
7
- additionalInfo: '<p>Some info</p>',
8
- age: 25,
9
- email: 'john@example.com',
10
- firstName: 'John',
11
- isActive: true,
12
- lastName: 'Doe',
13
- phoneNumber: '123-456-7890',
14
- };
15
-
16
- const person = Person.fromJSON(personData);
17
- const errors = await person.validate();
18
-
19
- expect(errors.length).toBe(0);
20
- });
21
-
22
- it('should validate a valid minor person with parent email', async () => {
23
- const personData = {
24
- additionalInfo: '<p>Minor info</p>',
25
- age: 16,
26
- email: 'jane@example.com',
27
- firstName: 'Jane',
28
- isActive: false,
29
- lastName: 'Smith',
30
- parentEmail: 'parent@example.com',
31
- };
32
-
33
- const person = Person.fromJSON(personData);
34
- const errors = await person.validate();
35
-
36
- expect(errors.length).toBe(0);
37
- });
38
-
39
- it('should fail validation when firstName is too short', async () => {
40
- const personData = {
41
- age: 25,
42
- email: 'john@example.com',
43
- firstName: 'J',
44
- lastName: 'Doe',
45
- };
46
-
47
- const person = Person.fromJSON(personData);
48
- const errors = await person.validate();
49
-
50
- expect(errors.length).toBeGreaterThan(0);
51
- const firstNameError = errors.find((e) => e.property === 'firstName');
52
- expect(firstNameError).toBeDefined();
53
- expect(firstNameError?.constraints).toHaveProperty('minLength');
54
- });
55
-
56
- it('should fail validation when firstName contains numbers', async () => {
57
- const personData = {
58
- age: 25,
59
- email: 'john@example.com',
60
- firstName: 'John123',
61
- lastName: 'Doe',
62
- };
63
-
64
- const person = Person.fromJSON(personData);
65
- const errors = await person.validate();
66
-
67
- expect(errors.length).toBeGreaterThan(0);
68
- const firstNameError = errors.find((e) => e.property === 'firstName');
69
- expect(firstNameError).toBeDefined();
70
- expect(firstNameError?.constraints).toHaveProperty('matches');
71
- });
72
-
73
- it('should fail validation when email is invalid', async () => {
74
- const personData = {
75
- age: 25,
76
- email: 'invalid-email',
77
- firstName: 'John',
78
- lastName: 'Doe',
79
- };
80
-
81
- const person = Person.fromJSON(personData);
82
- const errors = await person.validate();
83
-
84
- expect(errors.length).toBeGreaterThan(0);
85
- const emailError = errors.find((e) => e.property === 'email');
86
- expect(emailError).toBeDefined();
87
- expect(emailError?.constraints).toHaveProperty('isEmail');
88
- });
89
-
90
- it('should fail validation when age is negative', async () => {
91
- const personData = {
92
- age: -5,
93
- email: 'john@example.com',
94
- firstName: 'John',
95
- lastName: 'Doe',
96
- };
97
-
98
- const person = Person.fromJSON(personData);
99
- const errors = await person.validate();
100
-
101
- expect(errors.length).toBeGreaterThan(0);
102
- const ageError = errors.find((e) => e.property === 'age');
103
- expect(ageError).toBeDefined();
104
- expect(ageError?.constraints).toHaveProperty('invalidAge');
105
- });
106
-
107
- it('should fail validation when age is too high', async () => {
108
- const personData = {
109
- age: 150,
110
- email: 'john@example.com',
111
- firstName: 'John',
112
- lastName: 'Doe',
113
- };
114
-
115
- const person = Person.fromJSON(personData);
116
- const errors = await person.validate();
117
-
118
- expect(errors.length).toBeGreaterThan(0);
119
- const ageError = errors.find((e) => e.property === 'age');
120
- expect(ageError).toBeDefined();
121
- expect(ageError?.constraints).toHaveProperty('invalidAge');
122
- });
123
-
124
- it('should require parentEmail for minors', async () => {
125
- const personData = {
126
- age: 16,
127
- email: 'jane@example.com',
128
- firstName: 'Jane',
129
- lastName: 'Smith',
130
- // parentEmail missing
131
- };
132
-
133
- const person = Person.fromJSON(personData);
134
- const errors = await person.validate();
135
-
136
- expect(errors.length).toBeGreaterThan(0);
137
- const parentEmailError = errors.find((e) => e.property === 'parentEmail');
138
- expect(parentEmailError).toBeDefined();
139
- expect(parentEmailError?.constraints).toHaveProperty('isNotEmpty');
140
- });
141
-
142
- it('should not require parentEmail for adults', async () => {
143
- const personData = {
144
- age: 25,
145
- email: 'john@example.com',
146
- firstName: 'John',
147
- lastName: 'Doe',
148
- // parentEmail not provided
149
- };
150
-
151
- const person = Person.fromJSON(personData);
152
- const errors = await person.validate();
153
-
154
- // Should not have parentEmail error
155
- const parentEmailError = errors.find((e) => e.property === 'parentEmail');
156
- expect(parentEmailError).toBeUndefined();
157
- });
158
- });
159
-
160
- describe('JSON Serialization Tests', () => {
161
- it('should exclude internalId from JSON output', () => {
162
- const personData = {
163
- age: 25,
164
- email: 'john@example.com',
165
- firstName: 'John',
166
- internalId: 'secret-123',
167
- isActive: true,
168
- lastName: 'Doe',
169
- };
170
-
171
- const person = Person.fromJSON(personData);
172
- const json = person.toJSON();
173
-
174
- expect(json).not.toHaveProperty('internalId');
175
- expect(json).toHaveProperty('firstName', 'John');
176
- expect(json).toHaveProperty('lastName', 'Doe');
177
- expect(json).toHaveProperty('email', 'john@example.com');
178
- expect(json).toHaveProperty('age', 25);
179
- expect(json).toHaveProperty('isActive', true);
180
- });
181
-
182
- it('should include phoneNumber for adults', () => {
183
- const personData = {
184
- age: 25,
185
- email: 'john@example.com',
186
- firstName: 'John',
187
- lastName: 'Doe',
188
- phoneNumber: '123-456-7890',
189
- };
190
-
191
- const person = Person.fromJSON(personData);
192
- const json = person.toJSON();
193
-
194
- expect(json).toHaveProperty('phoneNumber', '123-456-7890');
195
- });
196
-
197
- it('should exclude phoneNumber for minors', () => {
198
- const personData = {
199
- age: 16,
200
- email: 'jane@example.com',
201
- firstName: 'Jane',
202
- lastName: 'Smith',
203
- parentEmail: 'parent@example.com',
204
- phoneNumber: '123-456-7890',
205
- };
206
-
207
- const person = Person.fromJSON(personData);
208
- const json = person.toJSON();
209
-
210
- expect(json).not.toHaveProperty('phoneNumber');
211
- expect(json).toHaveProperty('firstName', 'Jane');
212
- expect(json).toHaveProperty('parentEmail', 'parent@example.com');
213
- });
214
- });
215
-
216
- describe('Field Type Tests', () => {
217
- it('should handle boolean field correctly', async () => {
218
- const personData = {
219
- age: 25,
220
- email: 'john@example.com',
221
- firstName: 'John',
222
- isActive: true,
223
- lastName: 'Doe',
224
- };
225
-
226
- const person = Person.fromJSON(personData);
227
- const errors = await person.validate();
228
-
229
- expect(errors.length).toBe(0);
230
- expect(person.isActive).toBe(true);
231
- });
232
-
233
- it('should handle HTML field correctly', async () => {
234
- const personData = {
235
- additionalInfo: '<p>This is <strong>HTML</strong> content</p>',
236
- age: 25,
237
- email: 'john@example.com',
238
- firstName: 'John',
239
- lastName: 'Doe',
240
- };
241
-
242
- const person = Person.fromJSON(personData);
243
- const errors = await person.validate();
244
-
245
- expect(errors.length).toBe(0);
246
- expect(person.additionalInfo).toBe('<p>This is <strong>HTML</strong> content</p>');
247
- });
248
- });
249
-
250
- describe('Edge Cases', () => {
251
- it('should handle missing required fields', async () => {
252
- const personData = {
253
- // Missing firstName, lastName, age
254
- email: 'john@example.com',
255
- };
256
-
257
- const person = Person.fromJSON(personData);
258
- const errors = await person.validate();
259
-
260
- expect(errors.length).toBeGreaterThan(0);
261
-
262
- const firstNameError = errors.find((e) => e.property === 'firstName');
263
- const lastNameError = errors.find((e) => e.property === 'lastName');
264
- const ageError = errors.find((e) => e.property === 'age');
265
-
266
- expect(firstNameError).toBeDefined();
267
- expect(lastNameError).toBeDefined();
268
- expect(ageError).toBeDefined();
269
- });
270
-
271
- it('should handle boundary age values', async () => {
272
- const personData = {
273
- age: 18, // Boundary between minor and adult
274
- email: 'john@example.com',
275
- firstName: 'John',
276
- lastName: 'Doe',
277
- };
278
-
279
- const person = Person.fromJSON(personData);
280
- const errors = await person.validate();
281
-
282
- expect(errors.length).toBe(0);
283
-
284
- // At 18, parentEmail should not be required
285
- const parentEmailError = errors.find((e) => e.property === 'parentEmail');
286
- expect(parentEmailError).toBeUndefined();
287
- });
288
- });
289
- });
1
+ import { Person } from './Person';
2
+
3
+ describe('Person Model', () => {
4
+ describe('Validation Tests', () => {
5
+ it('should validate a valid adult person', async () => {
6
+ const personData = {
7
+ additionalInfo: '<p>Some info</p>',
8
+ age: 25,
9
+ email: 'john@example.com',
10
+ firstName: 'John',
11
+ isActive: true,
12
+ lastName: 'Doe',
13
+ phoneNumber: '123-456-7890',
14
+ };
15
+
16
+ const person = Person.fromJSON(personData);
17
+ const errors = await person.validate();
18
+
19
+ expect(errors.length).toBe(0);
20
+ });
21
+
22
+ it('should validate a valid minor person with parent email', async () => {
23
+ const personData = {
24
+ additionalInfo: '<p>Minor info</p>',
25
+ age: 16,
26
+ email: 'jane@example.com',
27
+ firstName: 'Jane',
28
+ isActive: false,
29
+ lastName: 'Smith',
30
+ parentEmail: 'parent@example.com',
31
+ };
32
+
33
+ const person = Person.fromJSON(personData);
34
+ const errors = await person.validate();
35
+
36
+ expect(errors.length).toBe(0);
37
+ });
38
+
39
+ it('should fail validation when firstName is too short', async () => {
40
+ const personData = {
41
+ age: 25,
42
+ email: 'john@example.com',
43
+ firstName: 'J',
44
+ lastName: 'Doe',
45
+ };
46
+
47
+ const person = Person.fromJSON(personData);
48
+ const errors = await person.validate();
49
+
50
+ expect(errors.length).toBeGreaterThan(0);
51
+ const firstNameError = errors.find((e) => e.property === 'firstName');
52
+ expect(firstNameError).toBeDefined();
53
+ expect(firstNameError?.constraints).toHaveProperty('minLength');
54
+ });
55
+
56
+ it('should fail validation when firstName contains numbers', async () => {
57
+ const personData = {
58
+ age: 25,
59
+ email: 'john@example.com',
60
+ firstName: 'John123',
61
+ lastName: 'Doe',
62
+ };
63
+
64
+ const person = Person.fromJSON(personData);
65
+ const errors = await person.validate();
66
+
67
+ expect(errors.length).toBeGreaterThan(0);
68
+ const firstNameError = errors.find((e) => e.property === 'firstName');
69
+ expect(firstNameError).toBeDefined();
70
+ expect(firstNameError?.constraints).toHaveProperty('matches');
71
+ });
72
+
73
+ it('should fail validation when email is invalid', async () => {
74
+ const personData = {
75
+ age: 25,
76
+ email: 'invalid-email',
77
+ firstName: 'John',
78
+ lastName: 'Doe',
79
+ };
80
+
81
+ const person = Person.fromJSON(personData);
82
+ const errors = await person.validate();
83
+
84
+ expect(errors.length).toBeGreaterThan(0);
85
+ const emailError = errors.find((e) => e.property === 'email');
86
+ expect(emailError).toBeDefined();
87
+ expect(emailError?.constraints).toHaveProperty('isEmail');
88
+ });
89
+
90
+ it('should fail validation when age is negative', async () => {
91
+ const personData = {
92
+ age: -5,
93
+ email: 'john@example.com',
94
+ firstName: 'John',
95
+ lastName: 'Doe',
96
+ };
97
+
98
+ const person = Person.fromJSON(personData);
99
+ const errors = await person.validate();
100
+
101
+ expect(errors.length).toBeGreaterThan(0);
102
+ const ageError = errors.find((e) => e.property === 'age');
103
+ expect(ageError).toBeDefined();
104
+ expect(ageError?.constraints).toHaveProperty('invalidAge');
105
+ });
106
+
107
+ it('should fail validation when age is too high', async () => {
108
+ const personData = {
109
+ age: 150,
110
+ email: 'john@example.com',
111
+ firstName: 'John',
112
+ lastName: 'Doe',
113
+ };
114
+
115
+ const person = Person.fromJSON(personData);
116
+ const errors = await person.validate();
117
+
118
+ expect(errors.length).toBeGreaterThan(0);
119
+ const ageError = errors.find((e) => e.property === 'age');
120
+ expect(ageError).toBeDefined();
121
+ expect(ageError?.constraints).toHaveProperty('invalidAge');
122
+ });
123
+
124
+ it('should require parentEmail for minors', async () => {
125
+ const personData = {
126
+ age: 16,
127
+ email: 'jane@example.com',
128
+ firstName: 'Jane',
129
+ lastName: 'Smith',
130
+ // parentEmail missing
131
+ };
132
+
133
+ const person = Person.fromJSON(personData);
134
+ const errors = await person.validate();
135
+
136
+ expect(errors.length).toBeGreaterThan(0);
137
+ const parentEmailError = errors.find((e) => e.property === 'parentEmail');
138
+ expect(parentEmailError).toBeDefined();
139
+ expect(parentEmailError?.constraints).toHaveProperty('isNotEmpty');
140
+ });
141
+
142
+ it('should not require parentEmail for adults', async () => {
143
+ const personData = {
144
+ age: 25,
145
+ email: 'john@example.com',
146
+ firstName: 'John',
147
+ lastName: 'Doe',
148
+ // parentEmail not provided
149
+ };
150
+
151
+ const person = Person.fromJSON(personData);
152
+ const errors = await person.validate();
153
+
154
+ // Should not have parentEmail error
155
+ const parentEmailError = errors.find((e) => e.property === 'parentEmail');
156
+ expect(parentEmailError).toBeUndefined();
157
+ });
158
+ });
159
+
160
+ describe('JSON Serialization Tests', () => {
161
+ it('should exclude internalId from JSON output', () => {
162
+ const personData = {
163
+ age: 25,
164
+ email: 'john@example.com',
165
+ firstName: 'John',
166
+ internalId: 'secret-123',
167
+ isActive: true,
168
+ lastName: 'Doe',
169
+ };
170
+
171
+ const person = Person.fromJSON(personData);
172
+ const json = person.toJSON();
173
+
174
+ expect(json).not.toHaveProperty('internalId');
175
+ expect(json).toHaveProperty('firstName', 'John');
176
+ expect(json).toHaveProperty('lastName', 'Doe');
177
+ expect(json).toHaveProperty('email', 'john@example.com');
178
+ expect(json).toHaveProperty('age', 25);
179
+ expect(json).toHaveProperty('isActive', true);
180
+ });
181
+
182
+ it('should include phoneNumber for adults', () => {
183
+ const personData = {
184
+ age: 25,
185
+ email: 'john@example.com',
186
+ firstName: 'John',
187
+ lastName: 'Doe',
188
+ phoneNumber: '123-456-7890',
189
+ };
190
+
191
+ const person = Person.fromJSON(personData);
192
+ const json = person.toJSON();
193
+
194
+ expect(json).toHaveProperty('phoneNumber', '123-456-7890');
195
+ });
196
+
197
+ it('should exclude phoneNumber for minors', () => {
198
+ const personData = {
199
+ age: 16,
200
+ email: 'jane@example.com',
201
+ firstName: 'Jane',
202
+ lastName: 'Smith',
203
+ parentEmail: 'parent@example.com',
204
+ phoneNumber: '123-456-7890',
205
+ };
206
+
207
+ const person = Person.fromJSON(personData);
208
+ const json = person.toJSON();
209
+
210
+ expect(json).not.toHaveProperty('phoneNumber');
211
+ expect(json).toHaveProperty('firstName', 'Jane');
212
+ expect(json).toHaveProperty('parentEmail', 'parent@example.com');
213
+ });
214
+ });
215
+
216
+ describe('Field Type Tests', () => {
217
+ it('should handle boolean field correctly', async () => {
218
+ const personData = {
219
+ age: 25,
220
+ email: 'john@example.com',
221
+ firstName: 'John',
222
+ isActive: true,
223
+ lastName: 'Doe',
224
+ };
225
+
226
+ const person = Person.fromJSON(personData);
227
+ const errors = await person.validate();
228
+
229
+ expect(errors.length).toBe(0);
230
+ expect(person.isActive).toBe(true);
231
+ });
232
+
233
+ it('should handle HTML field correctly', async () => {
234
+ const personData = {
235
+ additionalInfo: '<p>This is <strong>HTML</strong> content</p>',
236
+ age: 25,
237
+ email: 'john@example.com',
238
+ firstName: 'John',
239
+ lastName: 'Doe',
240
+ };
241
+
242
+ const person = Person.fromJSON(personData);
243
+ const errors = await person.validate();
244
+
245
+ expect(errors.length).toBe(0);
246
+ expect(person.additionalInfo).toBe('<p>This is <strong>HTML</strong> content</p>');
247
+ });
248
+ });
249
+
250
+ describe('Edge Cases', () => {
251
+ it('should handle missing required fields', async () => {
252
+ const personData = {
253
+ // Missing firstName, lastName, age
254
+ email: 'john@example.com',
255
+ };
256
+
257
+ const person = Person.fromJSON(personData);
258
+ const errors = await person.validate();
259
+
260
+ expect(errors.length).toBeGreaterThan(0);
261
+
262
+ const firstNameError = errors.find((e) => e.property === 'firstName');
263
+ const lastNameError = errors.find((e) => e.property === 'lastName');
264
+ const ageError = errors.find((e) => e.property === 'age');
265
+
266
+ expect(firstNameError).toBeDefined();
267
+ expect(lastNameError).toBeDefined();
268
+ expect(ageError).toBeDefined();
269
+ });
270
+
271
+ it('should handle boundary age values', async () => {
272
+ const personData = {
273
+ age: 18, // Boundary between minor and adult
274
+ email: 'john@example.com',
275
+ firstName: 'John',
276
+ lastName: 'Doe',
277
+ };
278
+
279
+ const person = Person.fromJSON(personData);
280
+ const errors = await person.validate();
281
+
282
+ expect(errors.length).toBe(0);
283
+
284
+ // At 18, parentEmail should not be required
285
+ const parentEmailError = errors.find((e) => e.property === 'parentEmail');
286
+ expect(parentEmailError).toBeUndefined();
287
+ });
288
+ });
289
+ });