@slingr/cli 0.0.2 → 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.
- package/LICENSE.txt +202 -0
- package/README.md +490 -319
- package/bin/dev.cmd +2 -2
- package/bin/dev.js +5 -5
- package/bin/run.cmd +2 -2
- package/bin/run.js +4 -4
- package/bin/slingr +1 -0
- package/dist/commands/build.d.ts +20 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +206 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/create-app.d.ts +0 -1
- package/dist/commands/create-app.d.ts.map +1 -1
- package/dist/commands/create-app.js +38 -57
- package/dist/commands/create-app.js.map +1 -1
- package/dist/commands/debug.d.ts +28 -0
- package/dist/commands/debug.d.ts.map +1 -0
- package/dist/commands/debug.js +474 -0
- package/dist/commands/debug.js.map +1 -0
- package/dist/commands/ds.d.ts +14 -1
- package/dist/commands/ds.d.ts.map +1 -1
- package/dist/commands/ds.js +450 -121
- package/dist/commands/ds.js.map +1 -1
- package/dist/commands/gql.d.ts +1 -1
- package/dist/commands/gql.d.ts.map +1 -1
- package/dist/commands/gql.js +190 -184
- package/dist/commands/gql.js.map +1 -1
- package/dist/commands/infra/down.d.ts.map +1 -1
- package/dist/commands/infra/down.js +8 -7
- package/dist/commands/infra/down.js.map +1 -1
- package/dist/commands/infra/up.d.ts.map +1 -1
- package/dist/commands/infra/up.js +8 -7
- package/dist/commands/infra/up.js.map +1 -1
- package/dist/commands/infra/update.d.ts +1 -0
- package/dist/commands/infra/update.d.ts.map +1 -1
- package/dist/commands/infra/update.js +33 -69
- package/dist/commands/infra/update.js.map +1 -1
- package/dist/commands/run.d.ts +29 -2
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +628 -130
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/setup.d.ts +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +34 -71
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/sync-metadata.d.ts +15 -0
- package/dist/commands/sync-metadata.d.ts.map +1 -0
- package/dist/commands/sync-metadata.js +225 -0
- package/dist/commands/sync-metadata.js.map +1 -0
- package/dist/commands/users.d.ts +30 -0
- package/dist/commands/users.d.ts.map +1 -0
- package/dist/commands/users.js +472 -0
- package/dist/commands/users.js.map +1 -0
- package/dist/commands/views.d.ts +11 -0
- package/dist/commands/views.d.ts.map +1 -0
- package/dist/commands/views.js +73 -0
- package/dist/commands/views.js.map +1 -0
- package/dist/projectStructure.d.ts +2 -2
- package/dist/projectStructure.d.ts.map +1 -1
- package/dist/projectStructure.js +281 -69
- package/dist/projectStructure.js.map +1 -1
- package/dist/scripts/generate-metadata.d.ts +13 -0
- package/dist/scripts/generate-metadata.d.ts.map +1 -0
- package/dist/scripts/generate-metadata.js +412 -0
- package/dist/scripts/generate-metadata.js.map +1 -0
- package/dist/scripts/generate-metadata.ts +498 -0
- package/dist/scripts/generate-schema.d.ts +1 -1
- package/dist/scripts/generate-schema.js +168 -74
- package/dist/scripts/generate-schema.js.map +1 -1
- package/dist/scripts/generate-schema.ts +258 -143
- package/dist/templates/.env.template +23 -0
- package/dist/templates/.firebaserc.template +5 -0
- package/dist/templates/.github/copilot-instructions.md.template +652 -17
- package/dist/templates/backend/Dockerfile.template +30 -0
- package/dist/templates/config/datasource.ts.template +12 -9
- package/dist/templates/config/jest.config.ts +30 -30
- package/dist/templates/config/jest.setup.ts +1 -1
- package/dist/templates/config/tsconfig.json.template +50 -29
- package/dist/templates/dataSources/mysql.ts.template +16 -13
- package/dist/templates/dataSources/postgres.ts.template +15 -13
- package/dist/templates/dataset-generator-script.ts.template +139 -139
- package/dist/templates/datasets/mysql-default/.slingr-schema.json.template +5 -0
- package/dist/templates/datasets/mysql-default/Address.jsonl.template +3 -3
- package/dist/templates/datasets/mysql-default/App.jsonl.template +4 -4
- package/dist/templates/datasets/mysql-default/Company.jsonl.template +3 -3
- package/dist/templates/datasets/mysql-default/Person.jsonl.template +2 -2
- package/dist/templates/datasets/mysql-default/User.jsonl.template +1 -0
- package/dist/templates/datasets/mysql-default/instructions.md.template +1 -0
- package/dist/templates/datasets/postgres-default/.slingr-schema.json.template +5 -0
- package/dist/templates/datasets/postgres-default/Address.jsonl.template +3 -3
- package/dist/templates/datasets/postgres-default/App.jsonl.template +4 -4
- package/dist/templates/datasets/postgres-default/Company.jsonl.template +3 -3
- package/dist/templates/datasets/postgres-default/Person.jsonl.template +2 -2
- package/dist/templates/datasets/postgres-default/User.jsonl.template +1 -0
- package/dist/templates/datasets/postgres-default/instructions.md.template +1 -0
- package/dist/templates/docker-compose.prod-test.yml.template +32 -0
- package/dist/templates/docker-compose.yml.template +24 -0
- package/dist/templates/docs/app-description.md.template +33 -33
- package/dist/templates/firebase.json.template +68 -0
- package/dist/templates/frontend/.umirc.ts.template +23 -0
- package/dist/templates/frontend/package.json.template +45 -0
- package/dist/templates/frontend/public/config.json +6 -0
- package/dist/templates/frontend/public/logo.svg +6 -0
- package/dist/templates/frontend/src/app.tsx.template +44 -0
- package/dist/templates/frontend/src/global.less.template +117 -0
- package/dist/templates/frontend/src/layouts/MainLayout.tsx.template +75 -0
- package/dist/templates/frontend/src/types/graphql-augmentation.d.ts.template +44 -0
- package/dist/templates/frontend/src/views/customViews/user/UserCreateView.tsx.template +18 -0
- package/dist/templates/frontend/src/views/customViews/user/UserEditView.tsx.template +29 -0
- package/dist/templates/frontend/src/views/customViews/user/UserReadView.tsx.template +24 -0
- package/dist/templates/frontend/src/views/customViews/user/UserTableView.tsx.template +38 -0
- package/dist/templates/frontend/src/views/customViews/welcome.tsx.template +34 -0
- package/dist/templates/frontend/tsconfig.json.template +50 -0
- package/dist/templates/gql/codegen.yml.template +25 -25
- package/dist/templates/gql/index.ts.template +17 -24
- package/dist/templates/gql/operations.graphql.template +30 -30
- package/dist/templates/ops/README.md.template +1045 -0
- package/dist/templates/ops/cloudbuild.yaml.template +161 -0
- package/dist/templates/ops/scripts/_utils.js.template +217 -0
- package/dist/templates/ops/scripts/deploy.js.template +145 -0
- package/dist/templates/ops/scripts/setup-gcp.js.template +330 -0
- package/dist/templates/ops/scripts/setup-secrets.js.template +76 -0
- package/dist/templates/ops/scripts/test-prod-local.js.template +49 -0
- package/dist/templates/package.json.template +50 -38
- package/dist/templates/pnpm-workspace.yaml.template +3 -0
- package/dist/templates/prompt-analysis.md.template +110 -110
- package/dist/templates/prompt-script-generation.md.template +258 -258
- package/dist/templates/src/Address.ts.template +28 -31
- package/dist/templates/src/App.ts.template +17 -61
- package/dist/templates/src/Company.ts.template +41 -47
- package/dist/templates/src/Models.test.ts.template +654 -654
- package/dist/templates/src/Person.test.ts.template +289 -289
- package/dist/templates/src/Person.ts.template +90 -105
- package/dist/templates/src/actions/index.ts.template +11 -11
- package/dist/templates/src/auth/permissions.ts.template +34 -0
- package/dist/templates/src/data/App.ts.template +48 -0
- package/dist/templates/src/data/User.ts.template +35 -0
- package/dist/templates/src/types/gql.d.ts.template +17 -17
- package/dist/templates/vscode/extensions.json +4 -3
- package/dist/templates/vscode/settings.json +17 -11
- package/dist/templates/workspace-package.json.template +21 -0
- package/dist/utils/buildCache.d.ts +12 -0
- package/dist/utils/buildCache.d.ts.map +1 -0
- package/dist/utils/buildCache.js +102 -0
- package/dist/utils/buildCache.js.map +1 -0
- package/dist/utils/checkFramework.d.ts +27 -0
- package/dist/utils/checkFramework.d.ts.map +1 -0
- package/dist/utils/checkFramework.js +104 -0
- package/dist/utils/checkFramework.js.map +1 -0
- package/dist/utils/datasourceParser.d.ts +11 -0
- package/dist/utils/datasourceParser.d.ts.map +1 -1
- package/dist/utils/datasourceParser.js +154 -56
- package/dist/utils/datasourceParser.js.map +1 -1
- package/dist/utils/dockerManager.d.ts +25 -0
- package/dist/utils/dockerManager.d.ts.map +1 -0
- package/dist/utils/dockerManager.js +281 -0
- package/dist/utils/dockerManager.js.map +1 -0
- package/dist/utils/infraFileParser.d.ts +26 -0
- package/dist/utils/infraFileParser.d.ts.map +1 -0
- package/dist/utils/infraFileParser.js +75 -0
- package/dist/utils/infraFileParser.js.map +1 -0
- package/dist/utils/jsonlLoader.d.ts +91 -12
- package/dist/utils/jsonlLoader.d.ts.map +1 -1
- package/dist/utils/jsonlLoader.js +674 -63
- package/dist/utils/jsonlLoader.js.map +1 -1
- package/dist/utils/model-analyzer.d.ts.map +1 -1
- package/dist/utils/model-analyzer.js +67 -13
- package/dist/utils/model-analyzer.js.map +1 -1
- package/dist/utils/userManagement.d.ts +57 -0
- package/dist/utils/userManagement.d.ts.map +1 -0
- package/dist/utils/userManagement.js +288 -0
- package/dist/utils/userManagement.js.map +1 -0
- package/dist/utils/viewsGenerator.d.ts +15 -0
- package/dist/utils/viewsGenerator.d.ts.map +1 -0
- package/dist/utils/viewsGenerator.js +311 -0
- package/dist/utils/viewsGenerator.js.map +1 -0
- package/oclif.manifest.json +445 -20
- package/package.json +29 -27
- package/src/templates/.env.template +23 -0
- package/src/templates/.firebaserc.template +5 -0
- package/src/templates/.github/copilot-instructions.md.template +652 -17
- package/src/templates/backend/Dockerfile.template +30 -0
- package/src/templates/config/datasource.ts.template +12 -9
- package/src/templates/config/jest.config.ts +30 -30
- package/src/templates/config/jest.setup.ts +1 -1
- package/src/templates/config/tsconfig.json.template +50 -29
- package/src/templates/dataSources/mysql.ts.template +16 -13
- package/src/templates/dataSources/postgres.ts.template +15 -13
- package/src/templates/dataset-generator-script.ts.template +139 -139
- package/src/templates/datasets/mysql-default/.slingr-schema.json.template +5 -0
- package/src/templates/datasets/mysql-default/Address.jsonl.template +3 -3
- package/src/templates/datasets/mysql-default/App.jsonl.template +4 -4
- package/src/templates/datasets/mysql-default/Company.jsonl.template +3 -3
- package/src/templates/datasets/mysql-default/Person.jsonl.template +2 -2
- package/src/templates/datasets/mysql-default/User.jsonl.template +1 -0
- package/src/templates/datasets/mysql-default/instructions.md.template +1 -0
- package/src/templates/datasets/postgres-default/.slingr-schema.json.template +5 -0
- package/src/templates/datasets/postgres-default/Address.jsonl.template +3 -3
- package/src/templates/datasets/postgres-default/App.jsonl.template +4 -4
- package/src/templates/datasets/postgres-default/Company.jsonl.template +3 -3
- package/src/templates/datasets/postgres-default/Person.jsonl.template +2 -2
- package/src/templates/datasets/postgres-default/User.jsonl.template +1 -0
- package/src/templates/datasets/postgres-default/instructions.md.template +1 -0
- package/src/templates/docker-compose.prod-test.yml.template +32 -0
- package/src/templates/docker-compose.yml.template +24 -0
- package/src/templates/docs/app-description.md.template +33 -33
- package/src/templates/firebase.json.template +68 -0
- package/src/templates/frontend/.umirc.ts.template +23 -0
- package/src/templates/frontend/package.json.template +45 -0
- package/src/templates/frontend/public/config.json +6 -0
- package/src/templates/frontend/public/logo.svg +6 -0
- package/src/templates/frontend/src/app.tsx.template +44 -0
- package/src/templates/frontend/src/global.less.template +117 -0
- package/src/templates/frontend/src/layouts/MainLayout.tsx.template +75 -0
- package/src/templates/frontend/src/types/graphql-augmentation.d.ts.template +44 -0
- package/src/templates/frontend/src/views/customViews/user/UserCreateView.tsx.template +18 -0
- package/src/templates/frontend/src/views/customViews/user/UserEditView.tsx.template +29 -0
- package/src/templates/frontend/src/views/customViews/user/UserReadView.tsx.template +24 -0
- package/src/templates/frontend/src/views/customViews/user/UserTableView.tsx.template +38 -0
- package/src/templates/frontend/src/views/customViews/welcome.tsx.template +34 -0
- package/src/templates/frontend/tsconfig.json.template +50 -0
- package/src/templates/gql/codegen.yml.template +25 -25
- package/src/templates/gql/index.ts.template +17 -24
- package/src/templates/gql/operations.graphql.template +30 -30
- package/src/templates/ops/README.md.template +1045 -0
- package/src/templates/ops/cloudbuild.yaml.template +161 -0
- package/src/templates/ops/scripts/_utils.js.template +217 -0
- package/src/templates/ops/scripts/deploy.js.template +145 -0
- package/src/templates/ops/scripts/setup-gcp.js.template +330 -0
- package/src/templates/ops/scripts/setup-secrets.js.template +76 -0
- package/src/templates/ops/scripts/test-prod-local.js.template +49 -0
- package/src/templates/package.json.template +50 -38
- package/src/templates/pnpm-workspace.yaml.template +3 -0
- package/src/templates/prompt-analysis.md.template +110 -110
- package/src/templates/prompt-script-generation.md.template +258 -258
- package/src/templates/src/Address.ts.template +28 -31
- package/src/templates/src/App.ts.template +17 -61
- package/src/templates/src/Company.ts.template +41 -47
- package/src/templates/src/Models.test.ts.template +654 -654
- package/src/templates/src/Person.test.ts.template +289 -289
- package/src/templates/src/Person.ts.template +90 -105
- package/src/templates/src/actions/index.ts.template +11 -11
- package/src/templates/src/auth/permissions.ts.template +34 -0
- package/src/templates/src/data/App.ts.template +48 -0
- package/src/templates/src/data/User.ts.template +35 -0
- package/src/templates/src/types/gql.d.ts.template +17 -17
- package/src/templates/vscode/extensions.json +4 -3
- package/src/templates/vscode/settings.json +17 -11
- package/src/templates/workspace-package.json.template +21 -0
- package/dist/templates/src/index.ts +0 -66
- 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
|
+
});
|