@player-ui/common-types-plugin 0.8.0--canary.307.9621 → 0.8.0-next.0

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 (36) hide show
  1. package/dist/CommonTypesPlugin.native.js +11903 -0
  2. package/dist/CommonTypesPlugin.native.js.map +1 -0
  3. package/dist/{index.cjs.js → cjs/index.cjs} +273 -233
  4. package/dist/cjs/index.cjs.map +1 -0
  5. package/dist/{index.esm.js → index.legacy-esm.js} +246 -220
  6. package/dist/index.mjs +782 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/package.json +26 -58
  9. package/src/__tests__/index.test.ts +198 -0
  10. package/src/data-types/types.ts +27 -37
  11. package/src/formats/__tests__/formats.test.ts +264 -0
  12. package/src/formats/__tests__/utils.test.ts +44 -0
  13. package/src/formats/index.ts +71 -69
  14. package/src/formats/utils.ts +16 -16
  15. package/src/index.ts +12 -12
  16. package/src/validators/__tests__/index.test.ts +472 -0
  17. package/src/validators/index.ts +67 -68
  18. package/types/data-types/types.d.ts +10 -0
  19. package/types/formats/index.d.ts +24 -0
  20. package/types/formats/utils.d.ts +41 -0
  21. package/types/index.d.ts +27 -0
  22. package/types/validators/index.d.ts +68 -0
  23. package/dist/common-types-plugin.dev.js +0 -11388
  24. package/dist/common-types-plugin.prod.js +0 -2
  25. package/dist/index.d.ts +0 -260
  26. package/dist/xlr/BooleanType.json +0 -72
  27. package/dist/xlr/CollectionType.json +0 -39
  28. package/dist/xlr/DateType.json +0 -55
  29. package/dist/xlr/IntegerNNType.json +0 -75
  30. package/dist/xlr/IntegerPosType.json +0 -75
  31. package/dist/xlr/IntegerType.json +0 -55
  32. package/dist/xlr/PhoneType.json +0 -55
  33. package/dist/xlr/StringType.json +0 -62
  34. package/dist/xlr/manifest.js +0 -21
  35. package/dist/xlr/manifest.json +0 -26
  36. package/src/data-types/refs.ts +0 -33
@@ -1,6 +1,6 @@
1
- import type { FormatType } from '@player-ui/player';
1
+ import type { FormatType } from "@player-ui/player";
2
2
 
3
- export const PLACEHOLDER = '#';
3
+ export const PLACEHOLDER = "#";
4
4
 
5
5
  /**
6
6
  * Remove any formatting characters in the 'mask' from 'value'
@@ -15,14 +15,14 @@ export const PLACEHOLDER = '#';
15
15
  export const removeFormatCharactersFromMaskedString = (
16
16
  value: string,
17
17
  mask: string,
18
- reserved: string[] = [PLACEHOLDER]
18
+ reserved: string[] = [PLACEHOLDER],
19
19
  ): string => {
20
20
  const reservedMatchesLength = mask
21
- .split('')
21
+ .split("")
22
22
  .filter((val) => reserved.includes(val)).length;
23
23
  let replacements = 0;
24
24
 
25
- return value.split('').reduce((newString, nextChar, nextIndex) => {
25
+ return value.split("").reduce((newString, nextChar, nextIndex) => {
26
26
  const maskedVal = mask[nextIndex];
27
27
 
28
28
  if (maskedVal === undefined) {
@@ -49,7 +49,7 @@ export const removeFormatCharactersFromMaskedString = (
49
49
  }
50
50
 
51
51
  return newString;
52
- }, '');
52
+ }, "");
53
53
  };
54
54
 
55
55
  /**
@@ -66,7 +66,7 @@ export const formatAsEnum = (
66
66
 
67
67
  /** If only 1 option is viable, autocomplete the value to the accepted one */
68
68
  autocomplete?: boolean;
69
- }
69
+ },
70
70
  ): string | undefined => {
71
71
  const autoCompletionsByOverlapCount = acceptedValues
72
72
  .reduce<
@@ -122,7 +122,7 @@ export const formatAsEnum = (
122
122
 
123
123
  return autoCompletionsByOverlapCount[0].target.substr(
124
124
  0,
125
- autoCompletionsByOverlapCount[0].count
125
+ autoCompletionsByOverlapCount[0].count,
126
126
  );
127
127
  };
128
128
 
@@ -136,13 +136,13 @@ export const formatAsEnum = (
136
136
  export const formatAsMasked = (
137
137
  value: string | number,
138
138
  valueCharMaskMatch: RegExp,
139
- mask: string
139
+ mask: string,
140
140
  ): string => {
141
141
  const valStr = String(value);
142
142
  let withMask = mask;
143
143
 
144
- if (valStr.trim() === '') {
145
- return '';
144
+ if (valStr.trim() === "") {
145
+ return "";
146
146
  }
147
147
 
148
148
  valStr.replace(valueCharMaskMatch, (match) => {
@@ -160,7 +160,7 @@ export const formatAsMasked = (
160
160
  */
161
161
  export const createMaskedNumericFormatter = (
162
162
  name: string,
163
- mask: string
163
+ mask: string,
164
164
  ): FormatType<
165
165
  string,
166
166
  string,
@@ -172,7 +172,7 @@ export const createMaskedNumericFormatter = (
172
172
  return {
173
173
  name,
174
174
  format: (value, options) => {
175
- if (typeof value !== 'string') {
175
+ if (typeof value !== "string") {
176
176
  return value;
177
177
  }
178
178
 
@@ -183,7 +183,7 @@ export const createMaskedNumericFormatter = (
183
183
  {
184
184
  autocomplete: true,
185
185
  ignoreCase: true,
186
- }
186
+ },
187
187
  );
188
188
 
189
189
  if (formattedUsingExceptions !== undefined) {
@@ -194,7 +194,7 @@ export const createMaskedNumericFormatter = (
194
194
  return formatAsMasked(value, /\d/g, mask);
195
195
  },
196
196
  deformat: (value, options) => {
197
- if (typeof value !== 'string') {
197
+ if (typeof value !== "string") {
198
198
  return value;
199
199
  }
200
200
 
@@ -209,7 +209,7 @@ export const createMaskedNumericFormatter = (
209
209
  }
210
210
  }
211
211
 
212
- return formatAsMasked(value, /\d/g, mask.replace(/[^#]/g, ''));
212
+ return formatAsMasked(value, /\d/g, mask.replace(/[^#]/g, ""));
213
213
  },
214
214
  };
215
215
  };
package/src/index.ts CHANGED
@@ -1,10 +1,9 @@
1
- import type { Player, ExtendedPlayerPlugin } from '@player-ui/player';
2
- import { TypesProviderPlugin } from '@player-ui/types-provider-plugin';
1
+ import type { Player, ExtendedPlayerPlugin } from "@player-ui/player";
2
+ import { TypesProviderPlugin } from "@player-ui/types-provider-plugin";
3
3
 
4
- import * as validators from './validators';
5
- import * as dataTypes from './data-types/types';
6
- import * as dataRefs from './data-types/refs';
7
- import * as formats from './formats';
4
+ import * as validators from "./validators";
5
+ import * as dataTypes from "./data-types/types";
6
+ import * as formats from "./formats";
8
7
  import type {
9
8
  BooleanType,
10
9
  IntegerType,
@@ -14,10 +13,11 @@ import type {
14
13
  CollectionType,
15
14
  DateType,
16
15
  PhoneType,
17
- } from './data-types/types';
16
+ } from "./data-types/types";
18
17
 
19
- export { validators, dataTypes, dataRefs, formats };
20
- export * from './formats/utils';
18
+ export { validators, dataTypes, formats };
19
+
20
+ export * from "./formats/utils";
21
21
 
22
22
  /**
23
23
  * Exposes a lot of common DataTypes, validations, and formats to Player instance.
@@ -36,11 +36,11 @@ export class CommonTypesPlugin
36
36
  typeof StringType,
37
37
  typeof CollectionType,
38
38
  typeof DateType,
39
- typeof PhoneType
39
+ typeof PhoneType,
40
40
  ]
41
41
  >
42
42
  {
43
- name = 'CommonTypes';
43
+ name = "CommonTypes";
44
44
 
45
45
  apply(player: Player) {
46
46
  player.registerPlugin(
@@ -48,7 +48,7 @@ export class CommonTypesPlugin
48
48
  types: Object.values(dataTypes),
49
49
  formats: Object.values(formats),
50
50
  validators: Object.entries(validators),
51
- })
51
+ }),
52
52
  );
53
53
  }
54
54
  }
@@ -0,0 +1,472 @@
1
+ import { describe, test, expect, it } from "vitest";
2
+ import {
3
+ BindingParser,
4
+ ConstantsController,
5
+ ExpressionEvaluator,
6
+ LocalModel,
7
+ withParser,
8
+ NoopLogger,
9
+ } from "@player-ui/player";
10
+ import type {
11
+ DataModelWithParser,
12
+ ValidationObject,
13
+ ValidatorContext,
14
+ } from "@player-ui/player";
15
+ import {
16
+ expression,
17
+ required,
18
+ readonly,
19
+ string,
20
+ integer,
21
+ collection,
22
+ length,
23
+ oneOf,
24
+ regex,
25
+ phone,
26
+ email,
27
+ zip,
28
+ min,
29
+ max,
30
+ } from "..";
31
+
32
+ /**
33
+ *
34
+ */
35
+ function create(
36
+ validation: Partial<ValidationObject> = {},
37
+ data: Record<string, unknown> = {},
38
+ ) {
39
+ const fullValidation: ValidationObject = {
40
+ message: "Something is wrong",
41
+ type: "unknown",
42
+ severity: "error",
43
+ trigger: "change",
44
+ ...validation,
45
+ };
46
+
47
+ const localModel = new LocalModel(data);
48
+ const parser = new BindingParser({
49
+ get: localModel.get,
50
+ set: localModel.set,
51
+ });
52
+ const model: DataModelWithParser = withParser(localModel, parser.parse);
53
+ const context: ValidatorContext = {
54
+ model,
55
+ parseBinding: parser.parse,
56
+ logger: new NoopLogger(),
57
+ validation: fullValidation,
58
+ constants: new ConstantsController(),
59
+ evaluate: new ExpressionEvaluator({ model }).evaluate,
60
+ schemaType: undefined,
61
+ };
62
+
63
+ return { context, validation: fullValidation };
64
+ }
65
+
66
+ describe("required", () => {
67
+ it("returns nothing for valid data", () => {
68
+ const { context } = create({
69
+ type: "required",
70
+ });
71
+
72
+ expect(required(context, 0)).toBe(undefined);
73
+ expect(required(context, [])).toBe(undefined);
74
+ expect(required(context, "foo")).toBe(undefined);
75
+ expect(required(context, {})).toBe(undefined);
76
+ });
77
+
78
+ it("errors on empty data", () => {
79
+ const { context } = create({
80
+ type: "required",
81
+ });
82
+
83
+ expect(required(context, "")?.message).toBe("A value is required");
84
+ expect(required(context, undefined)?.message).toBe("A value is required");
85
+ expect(required(context, null)?.message).toBe("A value is required");
86
+ });
87
+
88
+ it("handles required-if expressions", () => {
89
+ const { context } = create(
90
+ {
91
+ type: "required",
92
+ },
93
+ { foo: "bar" },
94
+ );
95
+
96
+ expect(required(context, undefined, { if: '{{foo}} == "foo"' })).toBe(
97
+ undefined,
98
+ );
99
+ expect(
100
+ required(context, undefined, { if: '{{foo}} == "bar"' })?.message,
101
+ ).toBe("A value is required");
102
+ });
103
+
104
+ it("handles required-if-not expressions", () => {
105
+ const { context } = create(
106
+ {
107
+ type: "required",
108
+ },
109
+ { foo: "bar" },
110
+ );
111
+
112
+ expect(
113
+ required(context, undefined, { ifNot: '{{foo}} == "foo"' })?.message,
114
+ ).toBe("A value is required");
115
+ expect(required(context, undefined, { ifNot: '{{foo}} == "bar"' })).toBe(
116
+ undefined,
117
+ );
118
+ });
119
+ });
120
+
121
+ describe("expressions", () => {
122
+ it("no error on valid expressions", () => {
123
+ const { context, validation } = create({
124
+ type: "expression",
125
+ exp: '"foo" == "foo"',
126
+ });
127
+
128
+ expect(expression(context, undefined, validation as any)).toBe(undefined);
129
+ });
130
+
131
+ it("error on invalid expressions", () => {
132
+ const { context, validation } = create({
133
+ type: "expression",
134
+ exp: '"foo" == "bar"',
135
+ });
136
+
137
+ expect(expression(context, undefined, validation as any)?.message).toBe(
138
+ "Expression evaluation failed",
139
+ );
140
+ });
141
+
142
+ it("does nothing with no expression", () => {
143
+ const { context, validation } = create({
144
+ type: "expression",
145
+ });
146
+
147
+ expect(expression(context, undefined, validation as any)).toBe(undefined);
148
+ });
149
+ });
150
+
151
+ describe("readonly", () => {
152
+ it("only returns an error", () => {
153
+ const { context } = create({ type: "readonly" });
154
+ expect(readonly(context, "foo")?.message).toBe("Value cannot be modified");
155
+ expect(readonly(context, undefined)?.message).toBe(
156
+ "Value cannot be modified",
157
+ );
158
+ });
159
+ });
160
+
161
+ describe("string", () => {
162
+ const { context } = create({ type: "string" });
163
+
164
+ it("works for strings", () => {
165
+ expect(string(context, "")).toBe(undefined);
166
+ expect(string(context, "foo")).toBe(undefined);
167
+ });
168
+
169
+ it("handles nullish values", () => {
170
+ expect(string(context, null)).toBe(undefined);
171
+ expect(string(context, undefined)).toBe(undefined);
172
+ });
173
+ it("errors on non-strings", () => {
174
+ expect(string(context, {})?.message).toBe("Value must be a string");
175
+ expect(string(context, [])?.message).toBe("Value must be a string");
176
+ expect(string(context, 1234)?.message).toBe("Value must be a string");
177
+ });
178
+
179
+ it("parameters on non-strings", () => {
180
+ expect(string(context, {})?.parameters?.type).toBe("object");
181
+ expect(string(context, [])?.parameters?.type).toBe("object");
182
+ expect(string(context, 1234)?.parameters?.type).toBe("number");
183
+ });
184
+ });
185
+
186
+ describe("integer", () => {
187
+ const { context } = create({ type: "string" });
188
+
189
+ it("works for integers", () => {
190
+ expect(integer(context, -100)).toBe(undefined);
191
+ expect(integer(context, 100)).toBe(undefined);
192
+ expect(integer(context, 0)).toBe(undefined);
193
+ });
194
+
195
+ it("handles nullish values", () => {
196
+ expect(integer(context, null)).toBe(undefined);
197
+ expect(integer(context, undefined)).toBe(undefined);
198
+ });
199
+
200
+ it("errors on non-integers", () => {
201
+ expect(integer(context, 1234.567)?.message).toBe(
202
+ "Value must be an integer",
203
+ );
204
+ });
205
+
206
+ it("parameters on non-integers", () => {
207
+ expect(integer(context, 1234.567)?.parameters?.type).toBe("number");
208
+ expect(integer(context, 1234.567)?.parameters?.flooredValue).toBe(1234);
209
+
210
+ expect(integer(context, "test")?.parameters?.type).toBe("string");
211
+ expect(integer(context, "test")?.parameters?.flooredValue).toBe(NaN);
212
+ });
213
+
214
+ it("errors on out of bounds integers", () => {
215
+ expect(integer(context, Number.MAX_SAFE_INTEGER + 1)?.message).toBe(
216
+ "Value must be an integer",
217
+ );
218
+ expect(integer(context, Number.MIN_SAFE_INTEGER - 1)?.message).toBe(
219
+ "Value must be an integer",
220
+ );
221
+ });
222
+
223
+ it("treats empty value as valid", () => {
224
+ expect(integer(context, "")).toBe(undefined);
225
+ });
226
+ });
227
+
228
+ describe("collection", () => {
229
+ const { context } = create({ type: "string" });
230
+
231
+ it("works for arrays", () => {
232
+ expect(collection(context, [])).toBe(undefined);
233
+ expect(collection(context, ["foo"])).toBe(undefined);
234
+ expect(collection(context, [1, 2, 3])).toBe(undefined);
235
+ });
236
+
237
+ it("handles nullish values", () => {
238
+ expect(collection(context, null)).toBe(undefined);
239
+ expect(collection(context, undefined)).toBe(undefined);
240
+ });
241
+
242
+ it("errors on non-arrays", () => {
243
+ expect(collection(context, 1234.567)?.message).toBe(
244
+ "Cannot set collection to non-array",
245
+ );
246
+ expect(collection(context, { 1: "a" })?.message).toBe(
247
+ "Cannot set collection to non-array",
248
+ );
249
+ });
250
+ });
251
+
252
+ describe("oneOf", () => {
253
+ const { context } = create({ type: "oneOf" });
254
+
255
+ it("does nothing if no options are provided", () => {
256
+ expect(oneOf(context, "foo")).toBe(undefined);
257
+ expect(oneOf(context, "foo", {} as any)).toBe(undefined);
258
+ });
259
+
260
+ it("handles nullish values", () => {
261
+ expect(oneOf(context, null, { options: ["foo", "bar"] })).toBe(undefined);
262
+ expect(oneOf(context, undefined, { options: ["foo", "bar"] })).toBe(
263
+ undefined,
264
+ );
265
+ });
266
+ it("works across types", () => {
267
+ expect(oneOf(context, "foo", { options: ["foo", "bar"] })).toBe(undefined);
268
+ expect(
269
+ oneOf(context, "not foo", { options: ["foo", "bar"] })?.message,
270
+ ).toBe("Invalid entry");
271
+ expect(oneOf(context, true, { options: ["foo", "bar", true] })).toBe(
272
+ undefined,
273
+ );
274
+ });
275
+ });
276
+
277
+ describe("regex", () => {
278
+ const { context } = create({ type: "regex" }, { foo: "asset" });
279
+
280
+ it("does nothing with invalid entries", () => {
281
+ expect(regex(context, undefined)).toBe(undefined);
282
+ expect(regex(context, null)).toBe(undefined);
283
+ expect(regex(context, "foo", { regex: 345 } as any)).toBe(undefined);
284
+ });
285
+
286
+ it("validates", () => {
287
+ expect(regex(context, "asset_text", { regex: "asset" })).toBe(undefined);
288
+ expect(regex(context, "", { regex: "asset" })).toBe(undefined);
289
+ expect(regex(context, "asset_text", { regex: "view" })?.message).toBe(
290
+ "Invalid entry",
291
+ );
292
+ expect(regex(context, "view_info", { regex: "view" })).toBe(undefined);
293
+ expect(regex(context, "view_info", { regex: "asset" })?.message).toBe(
294
+ "Invalid entry",
295
+ );
296
+ expect(regex(context, "FOO", { regex: "foo" })?.message).toBe(
297
+ "Invalid entry",
298
+ );
299
+ // i ignores case
300
+ expect(regex(context, "FOO", { regex: "/foo/i" })).toBe(undefined);
301
+
302
+ // Regex uses data reference
303
+ expect(regex(context, "asset_text", { regex: "{{foo}}" })).toBe(undefined);
304
+ expect(regex(context, "asset_text", { regex: "@[{{foo}}]@" })).toBe(
305
+ undefined,
306
+ );
307
+
308
+ expect(regex(context, "asset_text", { regex: "a{{foo}}" })?.message).toBe(
309
+ "Invalid entry",
310
+ );
311
+ expect(regex(context, "view_info", { regex: "{{foo}}" })?.message).toBe(
312
+ "Invalid entry",
313
+ );
314
+ });
315
+ });
316
+
317
+ describe("length", () => {
318
+ const { context } = create({ type: "length" });
319
+
320
+ it("works on strings", () => {
321
+ expect(length(context, "123", { exact: 3 })).toBe(undefined);
322
+ expect(length(context, "123", { exact: 5 })?.message).toBe(
323
+ "Must be exactly 5 characters long",
324
+ );
325
+ expect(
326
+ length(context, "123", { exact: 5 })?.parameters?.validationLength,
327
+ ).toBe(3);
328
+
329
+ expect(length(context, "123", { min: 3 })).toBe(undefined);
330
+ expect(length(context, "123", { min: 10 })?.message).toBe(
331
+ "At least 10 characters needed",
332
+ );
333
+ expect(
334
+ length(context, "123", { min: 10 })?.parameters?.validationLength,
335
+ ).toBe(3);
336
+
337
+ expect(length(context, "12345", { max: 3 })?.message).toBe(
338
+ "Up to 3 characters allowed",
339
+ );
340
+ expect(
341
+ length(context, "12345", { max: 3 })?.parameters?.validationLength,
342
+ ).toBe(5);
343
+ expect(length(context, "12345", { max: 10 })).toBe(undefined);
344
+ });
345
+ it("works on objects", () => {
346
+ expect(length(context, { 1: "1", 2: "2", 3: "3" }, { exact: 3 })).toBe(
347
+ undefined,
348
+ );
349
+ expect(
350
+ length(context, { a: "a", b: "b", c: "c" }, { exact: 5 })?.message,
351
+ ).toBe("Must be exactly 5 items long");
352
+ });
353
+
354
+ it("works on arrays", () => {
355
+ expect(length(context, ["a", "b", "c"], { exact: 3 })).toBe(undefined);
356
+ expect(length(context, ["a", "b", "c"], { exact: 5 })?.message).toBe(
357
+ "Must be exactly 5 items long",
358
+ );
359
+ });
360
+
361
+ it("does nothing when no length is present", () => {
362
+ expect(length(context, "123")).toBe(undefined);
363
+ });
364
+
365
+ it("does nothing if it cant determine the length", () => {
366
+ expect(length(context, undefined, { exact: 10 })).toBe(undefined);
367
+ expect(length(context, null, { exact: 10 })).toBe(undefined);
368
+ expect(length(context, 1234)).toBe(undefined);
369
+ });
370
+ });
371
+
372
+ test("min", () => {
373
+ const { context } = create({ type: "min" });
374
+
375
+ expect(min(context, undefined, { value: 1 })).toBeUndefined();
376
+ expect(min(context, null, { value: 1 })).toBeUndefined();
377
+
378
+ expect(min(context, 1)).toBeUndefined();
379
+ expect(min(context, 1, { value: 1 })).toBeUndefined();
380
+ expect(min(context, 2, { value: 1 })).toBeUndefined();
381
+ expect(min(context, 0, { value: 1 })).toStrictEqual({
382
+ message: "Must be at least 1",
383
+ });
384
+ });
385
+
386
+ test("max", () => {
387
+ const { context } = create({ type: "min" });
388
+ expect(max(context, undefined, { value: 1 })).toBeUndefined();
389
+ expect(max(context, null, { value: 1 })).toBeUndefined();
390
+ expect(max(context, 1)).toBeUndefined();
391
+ expect(max(context, 1, { value: 1 })).toBeUndefined();
392
+ expect(max(context, 2, { value: 1 })).toStrictEqual({
393
+ message: "Cannot exceed 1",
394
+ });
395
+ expect(max(context, 0, { value: 1 })).toBeUndefined();
396
+ });
397
+
398
+ test("email", () => {
399
+ const { context } = create({ type: "email" });
400
+ expect(email(context, undefined)).toBeUndefined();
401
+ expect(email(context, null)).toBeUndefined();
402
+
403
+ expect(email(context, "abc.xyz@pqr.com")).toBeUndefined();
404
+ expect(email(context, "")).toBeUndefined();
405
+ expect(email(context, "x.com")).toStrictEqual({
406
+ message: "Improper email format",
407
+ });
408
+ });
409
+
410
+ describe("phone", () => {
411
+ const { context } = create({ type: "phone" });
412
+ const invalid = { message: "Invalid phone number" };
413
+ it("works for good values", () => {
414
+ expect(phone(context, "1234567890")).toBeUndefined();
415
+ expect(phone(context, "")).toBeUndefined();
416
+ expect(phone(context, "345-222-1212")).toBeUndefined();
417
+ expect(phone(context, "+1-345-222-1212")).toBeUndefined();
418
+ expect(phone(context, "3452221212")).toBeUndefined();
419
+ expect(phone(context, "13452221212")).toBeUndefined();
420
+ expect(phone(context, "1 345 222 1212")).toBeUndefined();
421
+ expect(phone(context, "345 222 1212")).toBeUndefined();
422
+ expect(phone(context, "(345) 222 1212")).toBeUndefined();
423
+ expect(phone(context, "(345)222-1212")).toBeUndefined();
424
+ });
425
+
426
+ it("handles nullish values", () => {
427
+ expect(phone(context, undefined)).toBeUndefined();
428
+ expect(phone(context, null)).toBeUndefined();
429
+ });
430
+
431
+ it("returns error for invalid values", () => {
432
+ expect(phone(context, "(345)222-121")).toStrictEqual(invalid);
433
+ expect(phone(context, "(345) 222-121")).toStrictEqual(invalid);
434
+ expect(phone(context, "(345)222-121B")).toStrictEqual(invalid);
435
+ expect(phone(context, "(2345)222-1212")).toStrictEqual(invalid);
436
+ expect(phone(context, "(345) aaa888-1212")).toStrictEqual(invalid);
437
+ expect(phone(context, "+2-345-222-1212")).toStrictEqual(invalid);
438
+ expect(phone(context, "+1-345-222-121")).toStrictEqual(invalid);
439
+ expect(phone(context, "3")).toStrictEqual(invalid);
440
+ expect(phone(context, "A")).toStrictEqual(invalid);
441
+ expect(phone(context, "+2-345-222-1212")).toStrictEqual(invalid);
442
+ });
443
+ });
444
+
445
+ test("zip", () => {
446
+ const { context } = create({ type: "zip" });
447
+ expect(zip(context, undefined)).toBeUndefined();
448
+ expect(zip(context, null)).toBeUndefined();
449
+ expect(zip(context, "21216-1213")).toBeUndefined();
450
+ expect(zip(context, "2122")).toStrictEqual({ message: "Invalid zip code" });
451
+ expect(zip(context, "")).toBeUndefined();
452
+ });
453
+
454
+ describe("testing localization overrides", () => {
455
+ it("should take the new message then the old message after rest", () => {
456
+ const { context } = create({
457
+ type: "required",
458
+ });
459
+ const newMessages = {
460
+ validation: {
461
+ required: "Wow thats like, super wrong",
462
+ },
463
+ };
464
+ context.constants.setTemporaryValues(newMessages, "constants");
465
+ expect(required(context, "")?.message).toStrictEqual(
466
+ newMessages.validation.required,
467
+ );
468
+
469
+ context.constants.clearTemporaryValues();
470
+ expect(required(context, "")?.message).toStrictEqual("A value is required");
471
+ });
472
+ });