Pop-up dictionary browser extension for language learning. Successor to Yomichan. (PERSONAL FORK)
at lambda-fork/main 1035 lines 36 kB view raw
1/* 2 * Copyright (C) 2023-2025 Yomitan Authors 3 * Copyright (C) 2020-2022 Yomichan Authors 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 */ 18 19import {describe, expect, test} from 'vitest'; 20import {JsonSchema} from '../ext/js/data/json-schema.js'; 21 22/** 23 * @param {import('ext/json-schema').Schema} schema 24 * @param {unknown} value 25 * @returns {boolean} 26 */ 27function schemaValidate(schema, value) { 28 return new JsonSchema(schema).isValid(value); 29} 30 31/** 32 * @param {import('ext/json-schema').Schema} schema 33 * @param {unknown} value 34 * @returns {import('ext/json-schema').Value} 35 */ 36function getValidValueOrDefault(schema, value) { 37 return new JsonSchema(schema).getValidValueOrDefault(value); 38} 39 40/** 41 * @param {import('ext/json-schema').Schema} schema 42 * @param {import('ext/json-schema').Value} value 43 * @returns {import('ext/json-schema').Value} 44 */ 45function createProxy(schema, value) { 46 return new JsonSchema(schema).createProxy(value); 47} 48 49 50describe('JsonSchema', () => { 51 describe('Validate1', () => { 52 /** @type {import('ext/json-schema').Schema} */ 53 const schema = { 54 allOf: [ 55 { 56 type: 'number', 57 }, 58 { 59 anyOf: [ 60 {minimum: 10, maximum: 100}, 61 {minimum: -100, maximum: -10}, 62 ], 63 }, 64 { 65 oneOf: [ 66 {multipleOf: 3}, 67 {multipleOf: 5}, 68 ], 69 }, 70 { 71 not: { 72 anyOf: [ 73 {multipleOf: 20}, 74 ], 75 }, 76 }, 77 ], 78 }; 79 80 /** 81 * @param {number} value 82 * @returns {boolean} 83 */ 84 const jsValidate = (value) => { 85 return ( 86 typeof value === 'number' && 87 ( 88 (value >= 10 && value <= 100) || 89 (value >= -100 && value <= -10) 90 ) && 91 ( 92 ( 93 (value % 3) === 0 || 94 (value % 5) === 0 95 ) && 96 (value % 15) !== 0 97 ) && 98 (value % 20) !== 0 99 ); 100 }; 101 102 test('works as expected', () => { 103 for (let i = -111; i <= 111; i++) { 104 const actual = schemaValidate(schema, i); 105 const expected = jsValidate(i); 106 expect(actual).toStrictEqual(expected); 107 } 108 }); 109 }); 110 111 describe('Validate2', () => { 112 /* eslint-disable @stylistic/no-multi-spaces */ 113 /** @type {{schema: import('ext/json-schema').Schema, inputs: {expected: boolean, value: unknown}[]}[]} */ 114 const data = [ 115 // String tests 116 { 117 schema: { 118 type: 'string', 119 }, 120 inputs: [ 121 {expected: false, value: null}, 122 {expected: false, value: void 0}, 123 {expected: false, value: 0}, 124 {expected: false, value: {}}, 125 {expected: false, value: []}, 126 {expected: true, value: ''}, 127 ], 128 }, 129 { 130 schema: { 131 type: 'string', 132 minLength: 2, 133 }, 134 inputs: [ 135 {expected: false, value: ''}, 136 {expected: false, value: '1'}, 137 {expected: true, value: '12'}, 138 {expected: true, value: '123'}, 139 ], 140 }, 141 { 142 schema: { 143 type: 'string', 144 maxLength: 2, 145 }, 146 inputs: [ 147 {expected: true, value: ''}, 148 {expected: true, value: '1'}, 149 {expected: true, value: '12'}, 150 {expected: false, value: '123'}, 151 ], 152 }, 153 { 154 schema: { 155 type: 'string', 156 pattern: 'test', 157 }, 158 inputs: [ 159 {expected: false, value: ''}, 160 {expected: true, value: 'test'}, 161 {expected: false, value: 'TEST'}, 162 {expected: true, value: 'ABCtestDEF'}, 163 {expected: false, value: 'ABCTESTDEF'}, 164 ], 165 }, 166 { 167 schema: { 168 type: 'string', 169 pattern: '^test$', 170 }, 171 inputs: [ 172 {expected: false, value: ''}, 173 {expected: true, value: 'test'}, 174 {expected: false, value: 'TEST'}, 175 {expected: false, value: 'ABCtestDEF'}, 176 {expected: false, value: 'ABCTESTDEF'}, 177 ], 178 }, 179 { 180 schema: { 181 type: 'string', 182 pattern: '^test$', 183 patternFlags: 'i', 184 }, 185 inputs: [ 186 {expected: false, value: ''}, 187 {expected: true, value: 'test'}, 188 {expected: true, value: 'TEST'}, 189 {expected: false, value: 'ABCtestDEF'}, 190 {expected: false, value: 'ABCTESTDEF'}, 191 ], 192 }, 193 { 194 schema: { 195 type: 'string', 196 pattern: '*', 197 }, 198 inputs: [ 199 {expected: false, value: ''}, 200 ], 201 }, 202 { 203 schema: { 204 type: 'string', 205 pattern: '.', 206 patternFlags: '?', 207 }, 208 inputs: [ 209 {expected: false, value: ''}, 210 ], 211 }, 212 213 // Const tests 214 { 215 schema: { 216 const: 32, 217 }, 218 inputs: [ 219 {expected: true, value: 32}, 220 {expected: false, value: 0}, 221 {expected: false, value: '32'}, 222 {expected: false, value: null}, 223 {expected: false, value: {a: 'b'}}, 224 {expected: false, value: [1, 2, 3]}, 225 ], 226 }, 227 { 228 schema: { 229 const: '32', 230 }, 231 inputs: [ 232 {expected: false, value: 32}, 233 {expected: false, value: 0}, 234 {expected: true, value: '32'}, 235 {expected: false, value: null}, 236 {expected: false, value: {a: 'b'}}, 237 {expected: false, value: [1, 2, 3]}, 238 ], 239 }, 240 { 241 schema: { 242 const: null, 243 }, 244 inputs: [ 245 {expected: false, value: 32}, 246 {expected: false, value: 0}, 247 {expected: false, value: '32'}, 248 {expected: true, value: null}, 249 {expected: false, value: {a: 'b'}}, 250 {expected: false, value: [1, 2, 3]}, 251 ], 252 }, 253 { 254 schema: { 255 const: {a: 'b'}, 256 }, 257 inputs: [ 258 {expected: false, value: 32}, 259 {expected: false, value: 0}, 260 {expected: false, value: '32'}, 261 {expected: false, value: null}, 262 {expected: false, value: {a: 'b'}}, 263 {expected: false, value: [1, 2, 3]}, 264 ], 265 }, 266 { 267 schema: { 268 const: [1, 2, 3], 269 }, 270 inputs: [ 271 {expected: false, value: 32}, 272 {expected: false, value: 0}, 273 {expected: false, value: '32'}, 274 {expected: false, value: null}, 275 {expected: false, value: {a: 'b'}}, 276 {expected: false, value: [1, 2, 3]}, 277 ], 278 }, 279 280 // Array contains tests 281 { 282 schema: { 283 type: 'array', 284 contains: {const: 32}, 285 }, 286 inputs: [ 287 {expected: false, value: []}, 288 {expected: true, value: [32]}, 289 {expected: true, value: [1, 32]}, 290 {expected: true, value: [1, 32, 1]}, 291 {expected: false, value: [33]}, 292 {expected: false, value: [1, 33]}, 293 {expected: false, value: [1, 33, 1]}, 294 ], 295 }, 296 297 // Number limits tests 298 { 299 schema: { 300 type: 'number', 301 minimum: 0, 302 }, 303 inputs: [ 304 {expected: false, value: -1}, 305 {expected: true, value: 0}, 306 {expected: true, value: 1}, 307 ], 308 }, 309 { 310 schema: { 311 type: 'number', 312 exclusiveMinimum: 0, 313 }, 314 inputs: [ 315 {expected: false, value: -1}, 316 {expected: false, value: 0}, 317 {expected: true, value: 1}, 318 ], 319 }, 320 { 321 schema: { 322 type: 'number', 323 maximum: 0, 324 }, 325 inputs: [ 326 {expected: true, value: -1}, 327 {expected: true, value: 0}, 328 {expected: false, value: 1}, 329 ], 330 }, 331 { 332 schema: { 333 type: 'number', 334 exclusiveMaximum: 0, 335 }, 336 inputs: [ 337 {expected: true, value: -1}, 338 {expected: false, value: 0}, 339 {expected: false, value: 1}, 340 ], 341 }, 342 343 // Integer limits tests 344 { 345 schema: { 346 type: 'integer', 347 minimum: 0, 348 }, 349 inputs: [ 350 {expected: false, value: -1}, 351 {expected: true, value: 0}, 352 {expected: true, value: 1}, 353 ], 354 }, 355 { 356 schema: { 357 type: 'integer', 358 exclusiveMinimum: 0, 359 }, 360 inputs: [ 361 {expected: false, value: -1}, 362 {expected: false, value: 0}, 363 {expected: true, value: 1}, 364 ], 365 }, 366 { 367 schema: { 368 type: 'integer', 369 maximum: 0, 370 }, 371 inputs: [ 372 {expected: true, value: -1}, 373 {expected: true, value: 0}, 374 {expected: false, value: 1}, 375 ], 376 }, 377 { 378 schema: { 379 type: 'integer', 380 exclusiveMaximum: 0, 381 }, 382 inputs: [ 383 {expected: true, value: -1}, 384 {expected: false, value: 0}, 385 {expected: false, value: 1}, 386 ], 387 }, 388 { 389 schema: { 390 type: 'integer', 391 multipleOf: 2, 392 }, 393 inputs: [ 394 {expected: true, value: -2}, 395 {expected: false, value: -1}, 396 {expected: true, value: 0}, 397 {expected: false, value: 1}, 398 {expected: true, value: 2}, 399 ], 400 }, 401 402 // Numeric type tests 403 { 404 schema: { 405 type: 'number', 406 }, 407 inputs: [ 408 {expected: true, value: 0}, 409 {expected: true, value: 0.5}, 410 {expected: true, value: 1}, 411 {expected: false, value: '0'}, 412 {expected: false, value: null}, 413 {expected: false, value: []}, 414 {expected: false, value: {}}, 415 ], 416 }, 417 { 418 schema: { 419 type: 'integer', 420 }, 421 inputs: [ 422 {expected: true, value: 0}, 423 {expected: false, value: 0.5}, 424 {expected: true, value: 1}, 425 {expected: false, value: '0'}, 426 {expected: false, value: null}, 427 {expected: false, value: []}, 428 {expected: false, value: {}}, 429 ], 430 }, 431 432 // Reference tests 433 { 434 schema: { 435 definitions: { 436 example: { 437 type: 'number', 438 }, 439 }, 440 $ref: '#/definitions/example', 441 }, 442 inputs: [ 443 {expected: true, value: 0}, 444 {expected: true, value: 0.5}, 445 {expected: true, value: 1}, 446 {expected: false, value: '0'}, 447 {expected: false, value: null}, 448 {expected: false, value: []}, 449 {expected: false, value: {}}, 450 ], 451 }, 452 { 453 schema: { 454 definitions: { 455 example: { 456 type: 'integer', 457 }, 458 }, 459 $ref: '#/definitions/example', 460 }, 461 inputs: [ 462 {expected: true, value: 0}, 463 {expected: false, value: 0.5}, 464 {expected: true, value: 1}, 465 {expected: false, value: '0'}, 466 {expected: false, value: null}, 467 {expected: false, value: []}, 468 {expected: false, value: {}}, 469 ], 470 }, 471 { 472 schema: { 473 definitions: { 474 example: { 475 type: 'object', 476 additionalProperties: false, 477 properties: { 478 test: { 479 $ref: '#/definitions/example', 480 }, 481 }, 482 }, 483 }, 484 $ref: '#/definitions/example', 485 }, 486 inputs: [ 487 {expected: false, value: 0}, 488 {expected: false, value: 0.5}, 489 {expected: false, value: 1}, 490 {expected: false, value: '0'}, 491 {expected: false, value: null}, 492 {expected: false, value: []}, 493 {expected: true, value: {}}, 494 {expected: false, value: {test: 0}}, 495 {expected: false, value: {test: 0.5}}, 496 {expected: false, value: {test: 1}}, 497 {expected: false, value: {test: '0'}}, 498 {expected: false, value: {test: null}}, 499 {expected: false, value: {test: []}}, 500 {expected: true, value: {test: {}}}, 501 {expected: true, value: {test: {test: {}}}}, 502 {expected: true, value: {test: {test: {test: {}}}}}, 503 ], 504 }, 505 ]; 506 /* eslint-enable @stylistic/no-multi-spaces */ 507 508 describe.each(data)('Schema %#', ({schema, inputs}) => { 509 test.each(inputs)(`schemaValidate(${JSON.stringify(schema)}, $value) -> $expected`, ({expected, value}) => { 510 const actual = schemaValidate(schema, value); 511 expect(actual).toStrictEqual(expected); 512 }); 513 }); 514 }); 515 516 describe('GetValidValueOrDefault1', () => { 517 /** @type {{schema: import('ext/json-schema').Schema, inputs: [value: unknown, expected: unknown][]}[]} */ 518 const data = [ 519 // Test value defaulting on objects with additionalProperties=false 520 { 521 schema: { 522 type: 'object', 523 required: ['test'], 524 properties: { 525 test: { 526 type: 'string', 527 default: 'default', 528 }, 529 }, 530 additionalProperties: false, 531 }, 532 inputs: [ 533 [ 534 void 0, 535 {test: 'default'}, 536 ], 537 [ 538 null, 539 {test: 'default'}, 540 ], 541 [ 542 0, 543 {test: 'default'}, 544 ], 545 [ 546 '', 547 {test: 'default'}, 548 ], 549 [ 550 [], 551 {test: 'default'}, 552 ], 553 [ 554 {}, 555 {test: 'default'}, 556 ], 557 [ 558 {test: 'value'}, 559 {test: 'value'}, 560 ], 561 [ 562 {test2: 'value2'}, 563 {test: 'default'}, 564 ], 565 [ 566 {test: 'value', test2: 'value2'}, 567 {test: 'value'}, 568 ], 569 ], 570 }, 571 572 // Test value defaulting on objects with additionalProperties=true 573 { 574 schema: { 575 type: 'object', 576 required: ['test'], 577 properties: { 578 test: { 579 type: 'string', 580 default: 'default', 581 }, 582 }, 583 additionalProperties: true, 584 }, 585 inputs: [ 586 [ 587 {}, 588 {test: 'default'}, 589 ], 590 [ 591 {test: 'value'}, 592 {test: 'value'}, 593 ], 594 [ 595 {test2: 'value2'}, 596 {test: 'default', test2: 'value2'}, 597 ], 598 [ 599 {test: 'value', test2: 'value2'}, 600 {test: 'value', test2: 'value2'}, 601 ], 602 ], 603 }, 604 605 // Test value defaulting on objects with additionalProperties={schema} 606 { 607 schema: { 608 type: 'object', 609 required: ['test'], 610 properties: { 611 test: { 612 type: 'string', 613 default: 'default', 614 }, 615 }, 616 additionalProperties: { 617 type: 'number', 618 default: 10, 619 }, 620 }, 621 inputs: [ 622 [ 623 {}, 624 {test: 'default'}, 625 ], 626 [ 627 {test: 'value'}, 628 {test: 'value'}, 629 ], 630 [ 631 {test2: 'value2'}, 632 {test: 'default', test2: 10}, 633 ], 634 [ 635 {test: 'value', test2: 'value2'}, 636 {test: 'value', test2: 10}, 637 ], 638 [ 639 {test2: 2}, 640 {test: 'default', test2: 2}, 641 ], 642 [ 643 {test: 'value', test2: 2}, 644 {test: 'value', test2: 2}, 645 ], 646 [ 647 {test: 'value', test2: 2, test3: null}, 648 {test: 'value', test2: 2, test3: 10}, 649 ], 650 [ 651 {test: 'value', test2: 2, test3: void 0}, 652 {test: 'value', test2: 2, test3: 10}, 653 ], 654 ], 655 }, 656 657 // Test value defaulting where hasOwnProperty is false 658 { 659 schema: { 660 type: 'object', 661 required: ['test'], 662 properties: { 663 test: { 664 type: 'string', 665 default: 'default', 666 }, 667 }, 668 }, 669 inputs: [ 670 [ 671 {}, 672 {test: 'default'}, 673 ], 674 [ 675 {test: 'value'}, 676 {test: 'value'}, 677 ], 678 [ 679 Object.create({test: 'value'}), 680 {test: 'default'}, 681 ], 682 ], 683 }, 684 { 685 schema: { 686 type: 'object', 687 required: ['toString'], 688 properties: { 689 toString: /** @type {import('ext/json-schema').SchemaObject} */ ({ 690 type: 'string', 691 default: 'default', 692 }), 693 }, 694 }, 695 inputs: [ 696 [ 697 {}, 698 {toString: 'default'}, 699 ], 700 [ 701 {toString: 'value'}, 702 {toString: 'value'}, 703 ], 704 [ 705 Object.create({toString: 'value'}), 706 {toString: 'default'}, 707 ], 708 ], 709 }, 710 711 // Test enum 712 { 713 schema: { 714 type: 'object', 715 required: ['test'], 716 properties: { 717 test: { 718 type: 'string', 719 default: 'value1', 720 enum: ['value1', 'value2', 'value3'], 721 }, 722 }, 723 }, 724 inputs: [ 725 [ 726 {test: 'value1'}, 727 {test: 'value1'}, 728 ], 729 [ 730 {test: 'value2'}, 731 {test: 'value2'}, 732 ], 733 [ 734 {test: 'value3'}, 735 {test: 'value3'}, 736 ], 737 [ 738 {test: 'value4'}, 739 {test: 'value1'}, 740 ], 741 ], 742 }, 743 744 // Test valid vs invalid default 745 { 746 schema: { 747 type: 'object', 748 required: ['test'], 749 properties: { 750 test: { 751 type: 'integer', 752 default: 2, 753 minimum: 1, 754 }, 755 }, 756 }, 757 inputs: [ 758 [ 759 {test: -1}, 760 {test: 2}, 761 ], 762 ], 763 }, 764 { 765 schema: { 766 type: 'object', 767 required: ['test'], 768 properties: { 769 test: { 770 type: 'integer', 771 default: 1, 772 minimum: 2, 773 }, 774 }, 775 }, 776 inputs: [ 777 [ 778 {test: -1}, 779 {test: -1}, 780 ], 781 ], 782 }, 783 784 // Test references 785 { 786 schema: { 787 definitions: { 788 example: { 789 type: 'number', 790 default: 0, 791 }, 792 }, 793 $ref: '#/definitions/example', 794 }, 795 inputs: [ 796 [ 797 1, 798 1, 799 ], 800 [ 801 null, 802 0, 803 ], 804 [ 805 'test', 806 0, 807 ], 808 [ 809 {test: 'value'}, 810 0, 811 ], 812 ], 813 }, 814 { 815 schema: { 816 definitions: { 817 example: { 818 type: 'object', 819 additionalProperties: false, 820 properties: { 821 test: { 822 $ref: '#/definitions/example', 823 }, 824 }, 825 }, 826 }, 827 $ref: '#/definitions/example', 828 }, 829 inputs: [ 830 [ 831 1, 832 {}, 833 ], 834 [ 835 null, 836 {}, 837 ], 838 [ 839 'test', 840 {}, 841 ], 842 [ 843 {}, 844 {}, 845 ], 846 [ 847 {test: {}}, 848 {test: {}}, 849 ], 850 [ 851 {test: 'value'}, 852 {test: {}}, 853 ], 854 [ 855 {test: {test: {}}}, 856 {test: {test: {}}}, 857 ], 858 ], 859 }, 860 ]; 861 862 describe.each(data)('Schema %#', ({schema, inputs}) => { 863 test.each(inputs)(`getValidValueOrDefault(${JSON.stringify(schema)}, %o) -> %o`, (value, expected) => { 864 const actual = getValidValueOrDefault(schema, value); 865 expect(actual).toStrictEqual(expected); 866 }); 867 }); 868 }); 869 870 describe('Proxy1', () => { 871 /* eslint-disable @stylistic/no-multi-spaces */ 872 /** @type {{schema: import('ext/json-schema').Schema, tests: {error: boolean, value?: import('ext/json-schema').Value, action: (value: import('core').SafeAny) => void}[]}[]} */ 873 const data = [ 874 // Object tests 875 { 876 schema: { 877 type: 'object', 878 required: ['test'], 879 additionalProperties: false, 880 properties: { 881 test: { 882 type: 'string', 883 default: 'default', 884 }, 885 }, 886 }, 887 tests: [ 888 {error: false, value: {test: 'default'}, action: (value) => { value.test = 'string'; }}, 889 {error: true, value: {test: 'default'}, action: (value) => { value.test = null; }}, 890 {error: true, value: {test: 'default'}, action: (value) => { delete value.test; }}, 891 {error: true, value: {test: 'default'}, action: (value) => { value.test2 = 'string'; }}, 892 {error: false, value: {test: 'default'}, action: (value) => { delete value.test2; }}, 893 ], 894 }, 895 { 896 schema: { 897 type: 'object', 898 required: ['test'], 899 additionalProperties: true, 900 properties: { 901 test: { 902 type: 'string', 903 default: 'default', 904 }, 905 }, 906 }, 907 tests: [ 908 {error: false, value: {test: 'default'}, action: (value) => { value.test = 'string'; }}, 909 {error: true, value: {test: 'default'}, action: (value) => { value.test = null; }}, 910 {error: true, value: {test: 'default'}, action: (value) => { delete value.test; }}, 911 {error: false, value: {test: 'default'}, action: (value) => { value.test2 = 'string'; }}, 912 {error: false, value: {test: 'default'}, action: (value) => { delete value.test2; }}, 913 ], 914 }, 915 { 916 schema: { 917 type: 'object', 918 required: ['test1'], 919 additionalProperties: false, 920 properties: { 921 test1: { 922 type: 'object', 923 required: ['test2'], 924 additionalProperties: false, 925 properties: { 926 test2: { 927 type: 'object', 928 required: ['test3'], 929 additionalProperties: false, 930 properties: { 931 test3: { 932 type: 'string', 933 default: 'default', 934 }, 935 }, 936 }, 937 }, 938 }, 939 }, 940 }, 941 tests: [ 942 {error: false, action: (value) => { value.test1.test2.test3 = 'string'; }}, 943 {error: true, action: (value) => { value.test1.test2.test3 = null; }}, 944 {error: true, action: (value) => { delete value.test1.test2.test3; }}, 945 {error: true, action: (value) => { value.test1.test2 = null; }}, 946 {error: true, action: (value) => { value.test1 = null; }}, 947 {error: true, action: (value) => { value.test4 = 'string'; }}, 948 {error: false, action: (value) => { delete value.test4; }}, 949 ], 950 }, 951 952 // Array tests 953 { 954 schema: { 955 type: 'array', 956 items: { 957 type: 'string', 958 default: 'default', 959 }, 960 }, 961 tests: [ 962 {error: false, value: ['default'], action: (value) => { value[0] = 'string'; }}, 963 {error: true, value: ['default'], action: (value) => { value[0] = null; }}, 964 {error: false, value: ['default'], action: (value) => { delete value[0]; }}, 965 {error: false, value: ['default'], action: (value) => { value[1] = 'string'; }}, 966 { 967 error: false, 968 value: ['default'], 969 action: (value) => { 970 value[1] = 'string'; 971 if (value.length !== 2) { throw new Error(`Invalid length; expected=2; actual=${value.length}`); } 972 if (typeof value.push !== 'function') { throw new Error(`Invalid push; expected=function; actual=${typeof value.push}`); } 973 }, 974 }, 975 ], 976 }, 977 978 // Reference tests 979 { 980 schema: { 981 definitions: { 982 example: { 983 type: 'object', 984 additionalProperties: false, 985 properties: { 986 test: { 987 $ref: '#/definitions/example', 988 }, 989 }, 990 }, 991 }, 992 $ref: '#/definitions/example', 993 }, 994 tests: [ 995 {error: false, value: {}, action: (value) => { value.test = {}; }}, 996 {error: false, value: {}, action: (value) => { value.test = {}; value.test.test = {}; }}, 997 {error: false, value: {}, action: (value) => { value.test = {test: {}}; }}, 998 {error: true, value: {}, action: (value) => { value.test = null; }}, 999 {error: true, value: {}, action: (value) => { value.test = 'string'; }}, 1000 {error: true, value: {}, action: (value) => { value.test = {}; value.test.test = 'string'; }}, 1001 {error: true, value: {}, action: (value) => { value.test = {test: 'string'}; }}, 1002 ], 1003 }, 1004 ]; 1005 /* eslint-enable @stylistic/no-multi-spaces */ 1006 1007 describe.each(data)('Schema %#', ({schema, tests}) => { 1008 test.each(tests)('proxy %#', ({error, value, action}) => { 1009 if (typeof value === 'undefined') { value = getValidValueOrDefault(schema, void 0); } 1010 value = structuredClone(value); 1011 expect(schemaValidate(schema, value)).toBe(true); 1012 const valueProxy = createProxy(schema, value); 1013 if (error) { 1014 expect(() => action(valueProxy)).toThrow(); 1015 } else { 1016 expect(() => action(valueProxy)).not.toThrow(); 1017 } 1018 }); 1019 }); 1020 1021 for (const {schema, tests} of data) { 1022 for (let {error, value, action} of tests) { 1023 if (typeof value === 'undefined') { value = getValidValueOrDefault(schema, void 0); } 1024 value = structuredClone(value); 1025 expect(schemaValidate(schema, value)).toBe(true); 1026 const valueProxy = createProxy(schema, value); 1027 if (error) { 1028 expect(() => action(valueProxy)).toThrow(); 1029 } else { 1030 expect(() => action(valueProxy)).not.toThrow(); 1031 } 1032 } 1033 } 1034 }); 1035});