@a2ui-sdk/utils 0.1.1 → 0.2.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/package.json +5 -4
- package/dist/0.8/dataBinding.test.d.ts +0 -6
- package/dist/0.8/dataBinding.test.js +0 -271
- package/dist/0.8/pathUtils.test.d.ts +0 -6
- package/dist/0.8/pathUtils.test.js +0 -211
- package/dist/0.9/dataBinding.test.d.ts +0 -6
- package/dist/0.9/dataBinding.test.js +0 -180
- package/dist/0.9/interpolation/evaluator.test.d.ts +0 -4
- package/dist/0.9/interpolation/evaluator.test.js +0 -699
- package/dist/0.9/interpolation/lexer.test.d.ts +0 -4
- package/dist/0.9/interpolation/lexer.test.js +0 -360
- package/dist/0.9/interpolation/parser.test.d.ts +0 -4
- package/dist/0.9/interpolation/parser.test.js +0 -314
- package/dist/0.9/interpolation.test.d.ts +0 -5
- package/dist/0.9/interpolation.test.js +0 -154
- package/dist/0.9/pathUtils.test.d.ts +0 -6
- package/dist/0.9/pathUtils.test.js +0 -310
- package/dist/0.9/validation.test.d.ts +0 -4
- package/dist/0.9/validation.test.js +0 -307
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for validation utilities.
|
|
3
|
-
*/
|
|
4
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
5
|
-
import { validationFunctions, evaluateCheckRule, evaluateChecks, resolveArgs, } from './validation.js';
|
|
6
|
-
describe('validationFunctions', () => {
|
|
7
|
-
describe('required', () => {
|
|
8
|
-
it('should fail for null', () => {
|
|
9
|
-
expect(validationFunctions.required({ value: null })).toBe(false);
|
|
10
|
-
});
|
|
11
|
-
it('should fail for undefined', () => {
|
|
12
|
-
expect(validationFunctions.required({ value: undefined })).toBe(false);
|
|
13
|
-
});
|
|
14
|
-
it('should fail for empty string', () => {
|
|
15
|
-
expect(validationFunctions.required({ value: '' })).toBe(false);
|
|
16
|
-
});
|
|
17
|
-
it('should fail for whitespace-only string', () => {
|
|
18
|
-
expect(validationFunctions.required({ value: ' ' })).toBe(false);
|
|
19
|
-
});
|
|
20
|
-
it('should pass for non-empty string', () => {
|
|
21
|
-
expect(validationFunctions.required({ value: 'hello' })).toBe(true);
|
|
22
|
-
});
|
|
23
|
-
it('should pass for number zero', () => {
|
|
24
|
-
expect(validationFunctions.required({ value: 0 })).toBe(true);
|
|
25
|
-
});
|
|
26
|
-
it('should pass for boolean false', () => {
|
|
27
|
-
expect(validationFunctions.required({ value: false })).toBe(true);
|
|
28
|
-
});
|
|
29
|
-
it('should fail for empty array', () => {
|
|
30
|
-
expect(validationFunctions.required({ value: [] })).toBe(false);
|
|
31
|
-
});
|
|
32
|
-
it('should pass for non-empty array', () => {
|
|
33
|
-
expect(validationFunctions.required({ value: [1, 2] })).toBe(true);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
describe('email', () => {
|
|
37
|
-
it('should pass for valid email', () => {
|
|
38
|
-
expect(validationFunctions.email({ value: 'test@example.com' })).toBe(true);
|
|
39
|
-
});
|
|
40
|
-
it('should pass for email with subdomain', () => {
|
|
41
|
-
expect(validationFunctions.email({ value: 'test@mail.example.com' })).toBe(true);
|
|
42
|
-
});
|
|
43
|
-
it('should fail for missing @', () => {
|
|
44
|
-
expect(validationFunctions.email({ value: 'testexample.com' })).toBe(false);
|
|
45
|
-
});
|
|
46
|
-
it('should fail for missing domain', () => {
|
|
47
|
-
expect(validationFunctions.email({ value: 'test@' })).toBe(false);
|
|
48
|
-
});
|
|
49
|
-
it('should fail for missing local part', () => {
|
|
50
|
-
expect(validationFunctions.email({ value: '@example.com' })).toBe(false);
|
|
51
|
-
});
|
|
52
|
-
it('should fail for non-string value', () => {
|
|
53
|
-
expect(validationFunctions.email({ value: 123 })).toBe(false);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
describe('regex', () => {
|
|
57
|
-
it('should pass when pattern matches', () => {
|
|
58
|
-
expect(validationFunctions.regex({
|
|
59
|
-
value: 'hello123',
|
|
60
|
-
pattern: '^[a-z]+\\d+$',
|
|
61
|
-
})).toBe(true);
|
|
62
|
-
});
|
|
63
|
-
it('should fail when pattern does not match', () => {
|
|
64
|
-
expect(validationFunctions.regex({
|
|
65
|
-
value: '123hello',
|
|
66
|
-
pattern: '^[a-z]+\\d+$',
|
|
67
|
-
})).toBe(false);
|
|
68
|
-
});
|
|
69
|
-
it('should fail for non-string value', () => {
|
|
70
|
-
expect(validationFunctions.regex({ value: 123, pattern: '\\d+' })).toBe(false);
|
|
71
|
-
});
|
|
72
|
-
it('should fail for invalid regex pattern', () => {
|
|
73
|
-
expect(validationFunctions.regex({ value: 'test', pattern: '[invalid' })).toBe(false);
|
|
74
|
-
});
|
|
75
|
-
it('should fail for non-string pattern', () => {
|
|
76
|
-
expect(validationFunctions.regex({ value: 'test', pattern: 123 })).toBe(false);
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
describe('length', () => {
|
|
80
|
-
it('should pass when length is within bounds', () => {
|
|
81
|
-
expect(validationFunctions.length({ value: 'hello', min: 3, max: 10 })).toBe(true);
|
|
82
|
-
});
|
|
83
|
-
it('should fail when length is below min', () => {
|
|
84
|
-
expect(validationFunctions.length({ value: 'hi', min: 3, max: 10 })).toBe(false);
|
|
85
|
-
});
|
|
86
|
-
it('should fail when length is above max', () => {
|
|
87
|
-
expect(validationFunctions.length({ value: 'hello world!', min: 3, max: 10 })).toBe(false);
|
|
88
|
-
});
|
|
89
|
-
it('should pass when only min is specified', () => {
|
|
90
|
-
expect(validationFunctions.length({ value: 'hello', min: 3 })).toBe(true);
|
|
91
|
-
});
|
|
92
|
-
it('should pass when only max is specified', () => {
|
|
93
|
-
expect(validationFunctions.length({ value: 'hi', max: 5 })).toBe(true);
|
|
94
|
-
});
|
|
95
|
-
it('should pass with no constraints', () => {
|
|
96
|
-
expect(validationFunctions.length({ value: 'anything' })).toBe(true);
|
|
97
|
-
});
|
|
98
|
-
it('should handle null/undefined value as empty string', () => {
|
|
99
|
-
expect(validationFunctions.length({ value: null, min: 0 })).toBe(true);
|
|
100
|
-
expect(validationFunctions.length({ value: undefined, min: 1 })).toBe(false);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
describe('numeric', () => {
|
|
104
|
-
it('should pass for valid number within bounds', () => {
|
|
105
|
-
expect(validationFunctions.numeric({ value: 5, min: 0, max: 10 })).toBe(true);
|
|
106
|
-
});
|
|
107
|
-
it('should fail for number below min', () => {
|
|
108
|
-
expect(validationFunctions.numeric({ value: -1, min: 0, max: 10 })).toBe(false);
|
|
109
|
-
});
|
|
110
|
-
it('should fail for number above max', () => {
|
|
111
|
-
expect(validationFunctions.numeric({ value: 15, min: 0, max: 10 })).toBe(false);
|
|
112
|
-
});
|
|
113
|
-
it('should pass for string number within bounds', () => {
|
|
114
|
-
expect(validationFunctions.numeric({ value: '5', min: 0, max: 10 })).toBe(true);
|
|
115
|
-
});
|
|
116
|
-
it('should fail for non-numeric string', () => {
|
|
117
|
-
expect(validationFunctions.numeric({ value: 'hello', min: 0, max: 10 })).toBe(false);
|
|
118
|
-
});
|
|
119
|
-
it('should pass with no constraints', () => {
|
|
120
|
-
expect(validationFunctions.numeric({ value: 100 })).toBe(true);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
describe('resolveArgs', () => {
|
|
125
|
-
it('should resolve path bindings', () => {
|
|
126
|
-
const args = { value: { path: '/user/name' } };
|
|
127
|
-
const dataModel = { user: { name: 'Alice' } };
|
|
128
|
-
const result = resolveArgs(args, dataModel, null);
|
|
129
|
-
expect(result).toEqual({ value: 'Alice' });
|
|
130
|
-
});
|
|
131
|
-
it('should pass through literal values', () => {
|
|
132
|
-
const args = { min: 0, max: 10, pattern: '^[a-z]+$' };
|
|
133
|
-
const result = resolveArgs(args, {}, null);
|
|
134
|
-
expect(result).toEqual({ min: 0, max: 10, pattern: '^[a-z]+$' });
|
|
135
|
-
});
|
|
136
|
-
it('should resolve relative paths with scope', () => {
|
|
137
|
-
const args = { value: { path: 'name' } };
|
|
138
|
-
const dataModel = { users: [{ name: 'Alice' }, { name: 'Bob' }] };
|
|
139
|
-
const result = resolveArgs(args, dataModel, '/users/0');
|
|
140
|
-
expect(result).toEqual({ value: 'Alice' });
|
|
141
|
-
});
|
|
142
|
-
it('should return empty object for undefined args', () => {
|
|
143
|
-
expect(resolveArgs(undefined, {}, null)).toEqual({});
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
describe('evaluateCheckRule', () => {
|
|
147
|
-
const baseContext = {
|
|
148
|
-
dataModel: {},
|
|
149
|
-
basePath: null,
|
|
150
|
-
};
|
|
151
|
-
describe('function calls', () => {
|
|
152
|
-
it('should evaluate a simple function call', () => {
|
|
153
|
-
const rule = {
|
|
154
|
-
call: 'required',
|
|
155
|
-
args: { value: 'hello' },
|
|
156
|
-
message: 'Required',
|
|
157
|
-
};
|
|
158
|
-
const context = {
|
|
159
|
-
dataModel: {},
|
|
160
|
-
basePath: null,
|
|
161
|
-
};
|
|
162
|
-
expect(evaluateCheckRule(rule, context)).toBe(true);
|
|
163
|
-
});
|
|
164
|
-
it('should fail for failing validation', () => {
|
|
165
|
-
const rule = {
|
|
166
|
-
call: 'required',
|
|
167
|
-
args: { value: '' },
|
|
168
|
-
message: 'Required',
|
|
169
|
-
};
|
|
170
|
-
expect(evaluateCheckRule(rule, baseContext)).toBe(false);
|
|
171
|
-
});
|
|
172
|
-
it('should resolve path bindings in args', () => {
|
|
173
|
-
const rule = {
|
|
174
|
-
call: 'required',
|
|
175
|
-
args: { value: { path: '/user/email' } },
|
|
176
|
-
message: 'Email required',
|
|
177
|
-
};
|
|
178
|
-
const context = {
|
|
179
|
-
dataModel: { user: { email: 'test@example.com' } },
|
|
180
|
-
basePath: null,
|
|
181
|
-
};
|
|
182
|
-
expect(evaluateCheckRule(rule, context)).toBe(true);
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
describe('boolean constants', () => {
|
|
186
|
-
it('should return true for { true: true }', () => {
|
|
187
|
-
const rule = { true: true, message: 'Always pass' };
|
|
188
|
-
expect(evaluateCheckRule(rule, baseContext)).toBe(true);
|
|
189
|
-
});
|
|
190
|
-
it('should return false for { false: false }', () => {
|
|
191
|
-
const rule = { false: false, message: 'Always fail' };
|
|
192
|
-
expect(evaluateCheckRule(rule, baseContext)).toBe(false);
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
describe('logical operators', () => {
|
|
196
|
-
it('should handle AND with all passing', () => {
|
|
197
|
-
const rule = {
|
|
198
|
-
and: [
|
|
199
|
-
{ call: 'required', args: { value: 'a' }, message: 'a required' },
|
|
200
|
-
{ call: 'required', args: { value: 'b' }, message: 'b required' },
|
|
201
|
-
],
|
|
202
|
-
message: 'All required',
|
|
203
|
-
};
|
|
204
|
-
expect(evaluateCheckRule(rule, baseContext)).toBe(true);
|
|
205
|
-
});
|
|
206
|
-
it('should handle AND with one failing', () => {
|
|
207
|
-
const rule = {
|
|
208
|
-
and: [
|
|
209
|
-
{ call: 'required', args: { value: 'a' }, message: 'a required' },
|
|
210
|
-
{ call: 'required', args: { value: '' }, message: 'b required' },
|
|
211
|
-
],
|
|
212
|
-
message: 'All required',
|
|
213
|
-
};
|
|
214
|
-
expect(evaluateCheckRule(rule, baseContext)).toBe(false);
|
|
215
|
-
});
|
|
216
|
-
it('should handle OR with one passing', () => {
|
|
217
|
-
const rule = {
|
|
218
|
-
or: [
|
|
219
|
-
{ call: 'required', args: { value: '' }, message: 'a required' },
|
|
220
|
-
{ call: 'required', args: { value: 'b' }, message: 'b required' },
|
|
221
|
-
],
|
|
222
|
-
message: 'One required',
|
|
223
|
-
};
|
|
224
|
-
expect(evaluateCheckRule(rule, baseContext)).toBe(true);
|
|
225
|
-
});
|
|
226
|
-
it('should handle OR with all failing', () => {
|
|
227
|
-
const rule = {
|
|
228
|
-
or: [
|
|
229
|
-
{ call: 'required', args: { value: '' }, message: 'a required' },
|
|
230
|
-
{ call: 'required', args: { value: '' }, message: 'b required' },
|
|
231
|
-
],
|
|
232
|
-
message: 'One required',
|
|
233
|
-
};
|
|
234
|
-
expect(evaluateCheckRule(rule, baseContext)).toBe(false);
|
|
235
|
-
});
|
|
236
|
-
it('should handle NOT', () => {
|
|
237
|
-
const rule = {
|
|
238
|
-
not: { call: 'required', args: { value: '' }, message: 'inner' },
|
|
239
|
-
message: 'Should be empty',
|
|
240
|
-
};
|
|
241
|
-
expect(evaluateCheckRule(rule, baseContext)).toBe(true);
|
|
242
|
-
});
|
|
243
|
-
});
|
|
244
|
-
describe('unknown functions', () => {
|
|
245
|
-
it('should return true for unknown functions (with warning)', () => {
|
|
246
|
-
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
247
|
-
const rule = {
|
|
248
|
-
call: 'unknownFunction',
|
|
249
|
-
args: { value: 'test' },
|
|
250
|
-
message: 'Unknown',
|
|
251
|
-
};
|
|
252
|
-
expect(evaluateCheckRule(rule, baseContext)).toBe(true);
|
|
253
|
-
expect(warnSpy).toHaveBeenCalledWith('[A2UI] Unknown validation function: unknownFunction');
|
|
254
|
-
warnSpy.mockRestore();
|
|
255
|
-
});
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
describe('evaluateChecks', () => {
|
|
259
|
-
it('should return valid=true for no checks', () => {
|
|
260
|
-
const result = evaluateChecks(undefined, {}, null);
|
|
261
|
-
expect(result).toEqual({ valid: true, errors: [] });
|
|
262
|
-
});
|
|
263
|
-
it('should return valid=true for empty checks array', () => {
|
|
264
|
-
const result = evaluateChecks([], {}, null);
|
|
265
|
-
expect(result).toEqual({ valid: true, errors: [] });
|
|
266
|
-
});
|
|
267
|
-
it('should collect all error messages for failing checks', () => {
|
|
268
|
-
const checks = [
|
|
269
|
-
{ call: 'required', args: { value: '' }, message: 'Field is required' },
|
|
270
|
-
{ call: 'email', args: { value: '' }, message: 'Must be a valid email' },
|
|
271
|
-
];
|
|
272
|
-
const result = evaluateChecks(checks, {}, null);
|
|
273
|
-
expect(result.valid).toBe(false);
|
|
274
|
-
expect(result.errors).toEqual([
|
|
275
|
-
'Field is required',
|
|
276
|
-
'Must be a valid email',
|
|
277
|
-
]);
|
|
278
|
-
});
|
|
279
|
-
it('should return valid=true when all checks pass', () => {
|
|
280
|
-
const checks = [
|
|
281
|
-
{
|
|
282
|
-
call: 'required',
|
|
283
|
-
args: { value: 'test@example.com' },
|
|
284
|
-
message: 'Required',
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
call: 'email',
|
|
288
|
-
args: { value: 'test@example.com' },
|
|
289
|
-
message: 'Invalid email',
|
|
290
|
-
},
|
|
291
|
-
];
|
|
292
|
-
const result = evaluateChecks(checks, {}, null);
|
|
293
|
-
expect(result).toEqual({ valid: true, errors: [] });
|
|
294
|
-
});
|
|
295
|
-
it('should resolve paths from data model', () => {
|
|
296
|
-
const checks = [
|
|
297
|
-
{
|
|
298
|
-
call: 'required',
|
|
299
|
-
args: { value: { path: '/form/email' } },
|
|
300
|
-
message: 'Email is required',
|
|
301
|
-
},
|
|
302
|
-
];
|
|
303
|
-
const dataModel = { form: { email: 'test@example.com' } };
|
|
304
|
-
const result = evaluateChecks(checks, dataModel, null);
|
|
305
|
-
expect(result).toEqual({ valid: true, errors: [] });
|
|
306
|
-
});
|
|
307
|
-
});
|