diff --git a/package-lock.json b/package-lock.json
index 803790740..b2d9e6b48 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -152,54 +152,6 @@
"z-schema": "^4.2.3"
}
},
- "@babel/cli": {
- "version": "7.12.17",
- "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.12.17.tgz",
- "integrity": "sha512-R9dQbDshWvAp3x5XjANsfthqka+ToEdDUonKgtALNgzQxgiUg2Xa4ZwKIcE84wnoiobIJFXF+TCM4ylJvUuW5w==",
- "requires": {
- "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents",
- "chokidar": "^3.4.0",
- "commander": "^4.0.1",
- "convert-source-map": "^1.1.0",
- "fs-readdir-recursive": "^1.1.0",
- "glob": "^7.0.0",
- "lodash": "^4.17.19",
- "make-dir": "^2.1.0",
- "slash": "^2.0.0",
- "source-map": "^0.5.0"
- },
- "dependencies": {
- "commander": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
- "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="
- },
- "make-dir": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
- "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
- "requires": {
- "pify": "^4.0.1",
- "semver": "^5.6.0"
- }
- },
- "pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
- },
- "slash": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
- "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A=="
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
- }
- }
- },
"@babel/code-frame": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
@@ -272,6 +224,7 @@
"version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz",
"integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==",
+ "dev": true,
"requires": {
"@babel/types": "^7.12.10"
}
@@ -639,6 +592,7 @@
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz",
"integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==",
+ "dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.10.4",
"@babel/plugin-syntax-object-rest-spread": "^7.8.0",
@@ -756,6 +710,7 @@
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz",
"integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==",
+ "dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.10.4"
}
@@ -1032,6 +987,7 @@
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz",
"integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==",
+ "dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.10.4"
}
@@ -1067,6 +1023,7 @@
"version": "7.12.12",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.12.tgz",
"integrity": "sha512-JDWGuzGNWscYcq8oJVCtSE61a5+XAOos+V0HrxnDieUus4UMnBEosDnY1VJqU5iZ4pA04QY7l0+JvHL1hZEfsw==",
+ "dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.12.10",
"@babel/helper-module-imports": "^7.12.5",
@@ -1112,41 +1069,6 @@
"@babel/helper-plugin-utils": "^7.10.4"
}
},
- "@babel/plugin-transform-runtime": {
- "version": "7.12.17",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.17.tgz",
- "integrity": "sha512-s+kIJxnaTj+E9Q3XxQZ5jOo+xcogSe3V78/iFQ5RmoT0jROdpcdxhfGdq/VLqW1hFSzw6VjqN8aQqTaAMixWsw==",
- "requires": {
- "@babel/helper-module-imports": "^7.12.13",
- "@babel/helper-plugin-utils": "^7.12.13",
- "semver": "^5.5.1"
- },
- "dependencies": {
- "@babel/helper-module-imports": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz",
- "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==",
- "requires": {
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-plugin-utils": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz",
- "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA=="
- },
- "@babel/types": {
- "version": "7.12.17",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz",
- "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==",
- "requires": {
- "@babel/helper-validator-identifier": "^7.12.11",
- "lodash": "^4.17.19",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
"@babel/plugin-transform-shorthand-properties": {
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz",
@@ -1312,90 +1234,6 @@
"@babel/plugin-transform-react-pure-annotations": "^7.12.1"
}
},
- "@babel/register": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.12.13.tgz",
- "integrity": "sha512-fnCeRXj970S9seY+973oPALQg61TRvAaW0nRDe1f4ytKqM3fZgsNXewTZWmqZedg74LFIRpg/11dsrPZZvYs2g==",
- "requires": {
- "find-cache-dir": "^2.0.0",
- "lodash": "^4.17.19",
- "make-dir": "^2.1.0",
- "pirates": "^4.0.0",
- "source-map-support": "^0.5.16"
- },
- "dependencies": {
- "find-cache-dir": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
- "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
- "requires": {
- "commondir": "^1.0.1",
- "make-dir": "^2.0.0",
- "pkg-dir": "^3.0.0"
- }
- },
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "requires": {
- "locate-path": "^3.0.0"
- }
- },
- "locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
- "requires": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
- }
- },
- "make-dir": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
- "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
- "requires": {
- "pify": "^4.0.1",
- "semver": "^5.6.0"
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "requires": {
- "p-limit": "^2.0.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
- },
- "pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
- },
- "pkg-dir": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
- "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
- "requires": {
- "find-up": "^3.0.0"
- }
- }
- }
- },
"@babel/runtime": {
"version": "7.12.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz",
@@ -1404,15 +1242,6 @@
"regenerator-runtime": "^0.13.4"
}
},
- "@babel/runtime-corejs2": {
- "version": "7.12.18",
- "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.12.18.tgz",
- "integrity": "sha512-1wlWco+J/wbzdblk2oxThE7PhN8hZDK9fFnEG77Z1TJ+1dwt7UJ5soH5JPqrBTazlVTXTIwCcFGXsH/7m9WdYQ==",
- "requires": {
- "core-js": "^2.6.5",
- "regenerator-runtime": "^0.13.4"
- }
- },
"@babel/runtime-corejs3": {
"version": "7.12.5",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.12.5.tgz",
@@ -5072,198 +4901,6 @@
"glob-to-regexp": "^0.3.0"
}
},
- "@nicolo-ribaudo/chokidar-2": {
- "version": "2.1.8-no-fsevents",
- "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.tgz",
- "integrity": "sha512-+nb9vWloHNNMFHjGofEam3wopE3m1yuambrrd/fnPc+lFOMB9ROTqQlche9ByFWNkdNqfSgR/kkQtQ8DzEWt2w==",
- "optional": true,
- "requires": {
- "anymatch": "^2.0.0",
- "async-each": "^1.0.1",
- "braces": "^2.3.2",
- "glob-parent": "^3.1.0",
- "inherits": "^2.0.3",
- "is-binary-path": "^1.0.0",
- "is-glob": "^4.0.0",
- "normalize-path": "^3.0.0",
- "path-is-absolute": "^1.0.0",
- "readdirp": "^2.2.1",
- "upath": "^1.1.1"
- },
- "dependencies": {
- "anymatch": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
- "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
- "optional": true,
- "requires": {
- "micromatch": "^3.1.4",
- "normalize-path": "^2.1.1"
- },
- "dependencies": {
- "normalize-path": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
- "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "optional": true,
- "requires": {
- "remove-trailing-separator": "^1.0.1"
- }
- }
- }
- },
- "binary-extensions": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
- "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
- "optional": true
- },
- "braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "optional": true,
- "requires": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "optional": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
- "optional": true,
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "optional": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "glob-parent": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
- "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
- "optional": true,
- "requires": {
- "is-glob": "^3.1.0",
- "path-dirname": "^1.0.0"
- },
- "dependencies": {
- "is-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
- "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "optional": true,
- "requires": {
- "is-extglob": "^2.1.0"
- }
- }
- }
- },
- "is-binary-path": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
- "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
- "optional": true,
- "requires": {
- "binary-extensions": "^1.0.0"
- }
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "optional": true,
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "optional": true,
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "optional": true,
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- }
- },
- "readdirp": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
- "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
- "optional": true,
- "requires": {
- "graceful-fs": "^4.1.11",
- "micromatch": "^3.1.10",
- "readable-stream": "^2.0.2"
- }
- },
- "to-regex-range": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
- "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
- "optional": true,
- "requires": {
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1"
- }
- }
- }
- },
"@nodelib/fs.scandir": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
@@ -6964,7 +6601,8 @@
"async-each": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
- "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ=="
+ "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+ "dev": true
},
"async-foreach": {
"version": "0.1.3",
@@ -7285,6 +6923,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
+ "dev": true,
"optional": true
},
"bindings": {
@@ -7835,6 +7474,7 @@
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.0.tgz",
"integrity": "sha512-JgQM9JS92ZbFR4P90EvmzNpSGhpPBGBSj10PILeDyYFwp4h2/D9OM03wsJ4zW1fEp4ka2DGrnUeD7FuvQ2aZ2Q==",
+ "dev": true,
"optional": true,
"requires": {
"anymatch": "~3.1.1",
@@ -8179,7 +7819,8 @@
"commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
- "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+ "dev": true
},
"compare-func": {
"version": "2.0.0",
@@ -11867,11 +11508,6 @@
"minipass": "^2.6.0"
}
},
- "fs-readdir-recursive": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
- "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA=="
- },
"fs-write-stream-atomic": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
@@ -13694,6 +13330,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
"optional": true,
"requires": {
"binary-extensions": "^2.0.0"
@@ -17545,7 +17182,8 @@
"path-dirname": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
- "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA="
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+ "dev": true
},
"path-exists": {
"version": "3.0.0",
@@ -17886,7 +17524,8 @@
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
},
"progress": {
"version": "2.0.3",
@@ -18538,6 +18177,7 @@
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -18551,7 +18191,8 @@
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
}
}
},
@@ -18571,6 +18212,7 @@
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+ "dev": true,
"optional": true,
"requires": {
"picomatch": "^2.2.1"
@@ -19132,14 +18774,6 @@
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
},
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "requires": {
- "glob": "^7.1.3"
- }
- },
"ripemd160": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
@@ -20558,6 +20192,7 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
"requires": {
"safe-buffer": "~5.1.0"
},
@@ -20565,7 +20200,8 @@
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
}
}
},
@@ -21864,7 +21500,8 @@
"upath": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
- "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="
+ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+ "dev": true
},
"uri-js": {
"version": "4.4.0",
@@ -21932,7 +21569,8 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
},
"util-promisify": {
"version": "2.1.0",
diff --git a/packages/api-explorer/__tests__/__snapshots__/index.test.jsx.snap b/packages/api-explorer/__tests__/__snapshots__/index.test.jsx.snap
index 53549b400..7f67e939f 100644
--- a/packages/api-explorer/__tests__/__snapshots__/index.test.jsx.snap
+++ b/packages/api-explorer/__tests__/__snapshots__/index.test.jsx.snap
@@ -4,7 +4,7 @@ exports[`DocAsync should do OAS dereferencing 1`] = `
"
oneOf request with a nested allOf
Try It
patch https://httpbin.org /pets curl --request PATCH \\\\
--url https://httpbin.org/pets \\\\
--header 'Content-Type: application/json' \\\\
- --data '{\\"pet_type\\":\\"Cat\\"}'
Try the API to see Results
allOf with a readOnly prop
Try It
put https://httpbin.org /pets curl --request PUT \\\\
+ --data '{\\"pet_type\\":\\"Cat\\"}'
Try the API to see Results
allOf with a readOnly prop
Try It
put https://httpbin.org /pets curl --request PUT \\\\
--url https://httpbin.org/pets \\\\
- --header 'Content-Type: application/json'
Try the API to see Results
"
+ --header 'Content-Type: application/json'
Try the API to see Results
"
`;
diff --git a/packages/api-explorer/package-lock.json b/packages/api-explorer/package-lock.json
index 7eea89286..177ccc2e9 100644
--- a/packages/api-explorer/package-lock.json
+++ b/packages/api-explorer/package-lock.json
@@ -2935,17 +2935,6 @@
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
"dev": true
},
- "clone-deep": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
- "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
- "dev": true,
- "requires": {
- "is-plain-object": "^2.0.4",
- "kind-of": "^6.0.2",
- "shallow-clone": "^3.0.0"
- }
- },
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -10271,15 +10260,6 @@
"safe-buffer": "^5.0.1"
}
},
- "shallow-clone": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
- "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
- "dev": true,
- "requires": {
- "kind-of": "^6.0.2"
- }
- },
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
@@ -12713,16 +12693,6 @@
}
}
},
- "webpack-merge": {
- "version": "5.7.3",
- "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.7.3.tgz",
- "integrity": "sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==",
- "dev": true,
- "requires": {
- "clone-deep": "^4.0.1",
- "wildcard": "^2.0.0"
- }
- },
"webpack-sources": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
@@ -12785,12 +12755,6 @@
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
},
- "wildcard": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
- "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
- "dev": true
- },
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
diff --git a/packages/api-explorer/package.json b/packages/api-explorer/package.json
index 93d888ce3..777881998 100644
--- a/packages/api-explorer/package.json
+++ b/packages/api-explorer/package.json
@@ -11,7 +11,7 @@
"directory": "packages/api-explorer"
},
"scripts": {
- "build": "webpack --config webpack.prod.js",
+ "build": "webpack --config webpack.config.js",
"lint": "eslint . --ext js --ext jsx",
"pretest": "npm run lint && npm run prettier",
"prettier": "prettier --list-different --write \"./**/**.{js,jsx}\"",
@@ -61,8 +61,7 @@
"react-dom": "^16.14.0",
"terser-webpack-plugin": "^4.1.0",
"webpack": "^4.41.0",
- "webpack-cli": "^3.3.9",
- "webpack-merge": "^5.1.3"
+ "webpack-cli": "^3.3.9"
},
"prettier": "@readme/eslint-config/prettier"
}
diff --git a/packages/api-explorer/src/form-components/MultiSchemaField.jsx b/packages/api-explorer/src/form-components/MultiSchemaField.jsx
index 99dda71ed..8444408db 100644
--- a/packages/api-explorer/src/form-components/MultiSchemaField.jsx
+++ b/packages/api-explorer/src/form-components/MultiSchemaField.jsx
@@ -227,7 +227,6 @@ class MultiSchemaField extends Component {
const {
baseType,
disabled,
- errorSchema,
formData,
idPrefix,
idSchema,
@@ -274,7 +273,6 @@ class MultiSchemaField extends Component {
{children}
- {errors && {errors}
}
{help && {help}
}
);
}
function CustomTemplate(props) {
- const { id, classNames, label, help, required, description, errors, children, schema, onKeyChange } = props;
+ const { id, classNames, label, help, required, description, children, schema, onKeyChange } = props;
const EditLabel = (
onKeyChange(event.target.value)} type="text" />
@@ -92,7 +91,6 @@ function CustomTemplate(props) {
{description && {description}
}
{children && {children}
}
- {errors && {errors}
}
{help && {help}
}
);
@@ -172,7 +170,6 @@ CustomTemplate.propTypes = {
children: PropTypes.node.isRequired,
classNames: PropTypes.string.isRequired,
description: PropTypes.node.isRequired,
- errors: PropTypes.node.isRequired,
help: PropTypes.node.isRequired,
id: PropTypes.node.isRequired,
label: PropTypes.string,
@@ -188,7 +185,6 @@ CustomTemplate.defaultProps = {
CustomTemplateShell.propTypes = {
children: PropTypes.node.isRequired,
classNames: PropTypes.string.isRequired,
- errors: PropTypes.node.isRequired,
help: PropTypes.node.isRequired,
};
diff --git a/packages/api-explorer/webpack.config.js b/packages/api-explorer/webpack.config.js
index 4dc901bb6..23b98c2b7 100644
--- a/packages/api-explorer/webpack.config.js
+++ b/packages/api-explorer/webpack.config.js
@@ -1,24 +1,33 @@
const path = require('path');
+const webpack = require('webpack');
+const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
entry: ['whatwg-fetch', './src/index.jsx'],
- externals: {
- '@readme/markdown': '@readme/markdown',
- '@readme/variable': '@readme/variable',
- react: {
- root: 'React',
- commonjs: 'react',
- commonjs2: 'react',
- amd: 'react',
- },
- 'react-dom': {
- root: 'ReactDOM',
- commonjs2: 'react-dom',
- commonjs: 'react-dom',
- amd: 'react-dom',
- umd: 'react-dom',
+ externals: [
+ '@readme/markdown',
+ '@readme/variable',
+ {
+ react: {
+ root: 'React',
+ commonjs: 'react',
+ commonjs2: 'react',
+ amd: 'react',
+ },
+ 'react-dom': {
+ root: 'ReactDOM',
+ commonjs2: 'react-dom',
+ commonjs: 'react-dom',
+ amd: 'react-dom',
+ umd: 'react-dom',
+ },
},
- },
+
+ // `@readme/ui` loads this in for the search components but unfortunately we aren't able to exclude this from being
+ // compiled into our dist, despite not using that component. If we treat it as a Webpack external it will thankfully
+ // be ignored.
+ 'react-instantsearch-dom',
+ ],
module: {
rules: [
{
@@ -45,11 +54,20 @@ module.exports = {
},
],
},
+ optimization: {
+ minimize: true,
+ minimizer: [new TerserPlugin()],
+ },
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
libraryTarget: 'commonjs2',
},
+ plugins: [
+ new webpack.DefinePlugin({
+ 'process.env.NODE_ENV': JSON.stringify('production'),
+ }),
+ ],
resolve: {
extensions: ['.js', '.json', '.jsx'],
},
diff --git a/packages/api-explorer/webpack.prod.js b/packages/api-explorer/webpack.prod.js
deleted file mode 100644
index 8e4f3a470..000000000
--- a/packages/api-explorer/webpack.prod.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true }] */
-const webpack = require('webpack');
-const { merge } = require('webpack-merge');
-const TerserPlugin = require('terser-webpack-plugin');
-
-const common = require('./webpack.config');
-
-module.exports = merge(common, {
- optimization: {
- minimize: true,
- minimizer: [new TerserPlugin()],
- },
- plugins: [
- new webpack.DefinePlugin({
- 'process.env.NODE_ENV': JSON.stringify('production'),
- }),
- ],
-});
diff --git a/packages/oas-form/.babelrc b/packages/oas-form/.babelrc
deleted file mode 100644
index 0d11e9ccb..000000000
--- a/packages/oas-form/.babelrc
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "presets": [
- "@babel/preset-react",
- "@babel/preset-env"
- ],
- "plugins": [
- "@babel/plugin-proposal-object-rest-spread",
- "@babel/plugin-proposal-class-properties",
- [
- "@babel/plugin-transform-runtime",
- {
- "corejs": 2
- }
- ]
- ],
- "env": {
- "development": {
- "plugins": [
- "@babel/plugin-transform-react-jsx"
- ]
- }
- }
-}
diff --git a/packages/oas-form/__tests__/ArrayField_test.js b/packages/oas-form/__tests__/ArrayField_test.js
index 38625d918..2df78b1a0 100644
--- a/packages/oas-form/__tests__/ArrayField_test.js
+++ b/packages/oas-form/__tests__/ArrayField_test.js
@@ -2,7 +2,7 @@ import React from 'react';
import { Simulate } from 'react-dom/test-utils';
-import { createFormComponent, submitForm } from './test_utils';
+import { createFormComponent } from './test_utils';
const ArrayKeyDataAttr = 'data-rjsf-itemkey';
const ExposedArrayKeyTemplate = function (props) {
@@ -34,8 +34,8 @@ const ExposedArrayKeyTemplate = function (props) {
};
describe('ArrayField', () => {
- const CustomComponent = props => {
- return {props.rawErrors}
;
+ const CustomComponent = () => {
+ return
;
};
describe('Unsupported array schema', () => {
@@ -137,27 +137,6 @@ describe('ArrayField', () => {
expect(node.querySelector('#custom')).not.toBeNull();
});
- it('should pass rawErrors down to custom array field templates', () => {
- const schema = {
- type: 'array',
- title: 'my list',
- description: 'my description',
- items: { type: 'string' },
- minItems: 2,
- };
-
- const { node } = createFormComponent({
- schema,
- ArrayFieldTemplate: CustomComponent,
- formData: [1],
- liveValidate: true,
- });
-
- const matches = node.querySelectorAll('#custom');
- expect(matches).toHaveLength(1);
- expect(matches[0]).toHaveTextContent('should NOT have fewer than 2 items');
- });
-
it('should contain no field in the list by default', () => {
const { node } = createFormComponent({ schema });
@@ -437,79 +416,6 @@ describe('ArrayField', () => {
expect(dropBtn).toBeNull();
});
- it('should force revalidation when a field is removed', () => {
- // refs #195
- const { node } = createFormComponent({
- schema: {
- ...schema,
- items: { ...schema.items, minLength: 4 },
- },
- formData: ['foo', 'bar!'],
- });
-
- try {
- Simulate.submit(node);
- } catch (e) {
- // Silencing error thrown as failure is expected here
- }
-
- expect(node.querySelectorAll('.has-error .error-detail')).toHaveLength(1);
-
- const dropBtns = node.querySelectorAll('.array-item-remove');
-
- Simulate.click(dropBtns[0]);
-
- expect(node.querySelectorAll('.has-error .error-detail')).toHaveLength(0);
- });
-
- it('should handle cleared field values in the array', () => {
- const schema = {
- type: 'array',
- items: { type: 'integer' },
- };
- const formData = [1, 2, 3];
- const { node, onChange, onError } = createFormComponent({
- liveValidate: true,
- schema,
- formData,
- });
-
- Simulate.change(node.querySelector('#root_1'), {
- target: { value: '' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: { 1: { __errors: ['should be integer'] } },
- errors: [
- {
- message: 'should be integer',
- name: 'type',
- params: { type: 'integer' },
- property: '[1]',
- schemaPath: '#/items/type',
- stack: '[1] should be integer',
- },
- ],
- formData: [1, null, 3],
- })
- );
-
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should be integer',
- name: 'type',
- params: { type: 'integer' },
- property: '[1]',
- schemaPath: '#/items/type',
- stack: '[1] should be integer',
- },
- ])
- );
- });
-
it('should render the input widgets with the expected ids', () => {
const { node } = createFormComponent({
schema,
@@ -657,65 +563,6 @@ describe('ArrayField', () => {
expect(inputs[3].value).toBe('Unknown');
});
- it('should not add minItems extra formData entries when schema item is a multiselect', () => {
- const schema = {
- type: 'object',
- properties: {
- multipleChoicesList: {
- type: 'array',
- minItems: 3,
- uniqueItems: true,
- items: {
- type: 'string',
- enum: ['Aramis', 'Athos', 'Porthos', "d'Artagnan"],
- },
- },
- },
- };
- const uiSchema = {
- multipleChoicesList: {
- 'ui:widget': 'checkboxes',
- },
- };
- let form = createFormComponent({
- schema,
- uiSchema,
- formData: {},
- liveValidate: true,
- noValidate: true,
- });
- submitForm(form.node);
-
- expect(form.onSubmit).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: { multipleChoicesList: [] },
- }),
- expect.anything()
- );
-
- form = createFormComponent({
- schema,
- uiSchema,
- formData: {},
- liveValidate: true,
- noValidate: false,
- });
- submitForm(form.node);
-
- expect(form.onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should NOT have fewer than 3 items',
- name: 'minItems',
- params: { limit: 3 },
- property: '.multipleChoicesList',
- schemaPath: '#/properties/multipleChoicesList/minItems',
- stack: '.multipleChoicesList should NOT have fewer than 3 items',
- },
- ])
- );
- });
-
it('should honor given formData, even when it does not meet ths minItems-requirement', () => {
const complexSchema = {
type: 'object',
@@ -859,21 +706,6 @@ describe('ArrayField', () => {
expect(node.querySelector('select').id).toBe('root');
});
-
- it('should pass rawErrors down to custom widgets', () => {
- const { node } = createFormComponent({
- schema,
- widgets: {
- SelectWidget: CustomComponent,
- },
- formData: ['foo', 'foo'],
- liveValidate: true,
- });
-
- const matches = node.querySelectorAll('#custom');
- expect(matches).toHaveLength(1);
- expect(matches[0]).toHaveTextContent('should NOT have duplicate items (items ## 1 and 0 are identical)');
- });
});
describe('CheckboxesWidget', () => {
@@ -944,33 +776,6 @@ describe('ArrayField', () => {
expect(node.querySelectorAll('.checkbox-inline')).toHaveLength(3);
});
-
- it('should pass rawErrors down to custom widgets', () => {
- const schema = {
- type: 'array',
- title: 'My field',
- items: {
- enum: ['foo', 'bar', 'fuzz'],
- type: 'string',
- },
- minItems: 3,
- uniqueItems: true,
- };
-
- const { node } = createFormComponent({
- schema,
- widgets: {
- CheckboxesWidget: CustomComponent,
- },
- uiSchema,
- formData: [],
- liveValidate: true,
- });
-
- const matches = node.querySelectorAll('#custom');
- expect(matches).toHaveLength(1);
- expect(matches[0]).toHaveTextContent('should NOT have fewer than 3 items');
- });
});
});
@@ -1051,31 +856,6 @@ describe('ArrayField', () => {
expect(node.querySelector('input[type=file]').id).toBe('root');
});
-
- it('should pass rawErrors down to custom widgets', () => {
- const schema = {
- type: 'array',
- title: 'My field',
- items: {
- type: 'string',
- format: 'data-url',
- },
- minItems: 5,
- };
-
- const { node } = createFormComponent({
- schema,
- widgets: {
- FileWidget: CustomComponent,
- },
- formData: [],
- liveValidate: true,
- });
-
- const matches = node.querySelectorAll('#custom');
- expect(matches).toHaveLength(1);
- expect(matches[0]).toHaveTextContent('should NOT have fewer than 5 items');
- });
});
describe('Nested lists', () => {
@@ -1110,44 +890,6 @@ describe('ArrayField', () => {
expect(node.querySelectorAll('fieldset fieldset')).toHaveLength(1);
});
-
- it('should pass rawErrors down to every level of custom widgets', () => {
- const CustomItem = props => {props.children}
;
- const CustomTemplate = props => {
- return (
-
- {props.items && props.items.map((p, i) =>
)}
-
{props.rawErrors && props.rawErrors.join(', ')}
-
- );
- };
-
- const schema = {
- type: 'array',
- title: 'A list of arrays',
- items: {
- type: 'array',
- title: 'A list of numbers',
- items: {
- type: 'number',
- },
- minItems: 3,
- },
- minItems: 2,
- };
-
- const { node } = createFormComponent({
- schema,
- ArrayFieldTemplate: CustomTemplate,
- formData: [[]],
- liveValidate: true,
- });
-
- const matches = node.querySelectorAll('#custom-error');
- expect(matches).toHaveLength(2);
- expect(matches[0]).toHaveTextContent('should NOT have fewer than 3 items');
- expect(matches[1]).toHaveTextContent('should NOT have fewer than 2 items');
- });
});
describe('Fixed items lists', () => {
diff --git a/packages/oas-form/__tests__/BooleanField_test.js b/packages/oas-form/__tests__/BooleanField_test.js
index 500f8c685..fb757b497 100644
--- a/packages/oas-form/__tests__/BooleanField_test.js
+++ b/packages/oas-form/__tests__/BooleanField_test.js
@@ -199,7 +199,6 @@ describe('BooleanField', () => {
it('formData should default to undefined', () => {
const { node, onSubmit } = createFormComponent({
schema: { type: 'boolean' },
- noValidate: true,
});
submitForm(node);
expect(onSubmit).toHaveBeenLastCalledWith(
diff --git a/packages/oas-form/__tests__/Form_test.js b/packages/oas-form/__tests__/Form_test.js
index 585428ad8..f7679d6fc 100644
--- a/packages/oas-form/__tests__/Form_test.js
+++ b/packages/oas-form/__tests__/Form_test.js
@@ -1,4 +1,3 @@
-/* eslint-disable global-require */
/* eslint-disable react/no-find-dom-node */
/* eslint-disable max-classes-per-file */
import React from 'react';
@@ -10,2032 +9,206 @@ import { createRef } from 'create-react-ref';
import Form from '../src';
import { createComponent, createFormComponent, setProps, submitForm } from './test_utils';
-const formExtraPropsList = [
- [{ omitExtraData: false }],
- [{ omitExtraData: true }],
- [{ omitExtraData: true, liveOmit: true }],
-];
+let createFormComponentFn;
-describe.each(formExtraPropsList)('Form with props: `%s`', formExtraProps => {
- let createFormComponentFn;
-
- beforeAll(() => {
- createFormComponentFn = props => createFormComponent({ ...props, ...formExtraProps });
- });
-
- describe('Empty schema', () => {
- it('should render a form tag', () => {
- const { node } = createFormComponentFn({ schema: {} });
-
- expect(node.tagName).toBe('FORM');
- });
-
- it('should render a submit button', () => {
- const { node } = createFormComponent({ schema: {} });
-
- expect(node.querySelectorAll('button[type=submit]')).toHaveLength(1);
- });
-
- it('should render children buttons', () => {
- const props = { schema: {} };
- const comp = renderIntoDocument(
-
- );
- const node = findDOMNode(comp);
- expect(node.querySelectorAll('button[type=submit]')).toHaveLength(2);
- });
-
- it("should render errors if schema isn't object", () => {
- const props = {
- schema: {
- type: 'object',
- title: 'object',
- properties: {
- firstName: 'some mame',
- address: {
- $ref: '#/definitions/address',
- },
- },
- definitions: {
- address: {
- street: 'some street',
- },
- },
- },
- };
- const comp = renderIntoDocument(
-
- );
- const node = findDOMNode(comp);
- expect(node.querySelector('.unsupported-field')).toHaveTextContent('Unknown field type undefined');
- });
- });
-
- describe('on component creation', () => {
- let onChangeProp;
- let formData;
- let schema;
-
- function createComponent() {
- renderIntoDocument(
-
- );
- }
-
- beforeEach(() => {
- onChangeProp = jest.fn();
- schema = {
- type: 'object',
- title: 'root object',
- required: ['count'],
- properties: {
- count: {
- type: 'number',
- default: 789,
- },
- },
- };
- });
-
- describe('when props.formData does not equal the default values', () => {
- beforeEach(() => {
- formData = {
- foo: 123,
- };
- createComponent();
- });
-
- it('should call props.onChange with current state', () => {
- expect(onChangeProp).toHaveBeenCalledTimes(1);
- expect(onChangeProp).toHaveBeenCalledWith({
- formData: { ...formData, count: 789 },
- schema,
- errorSchema: {},
- errors: [],
- edit: true,
- uiSchema: {},
- idSchema: { $id: 'root', count: { $id: 'root_count' } },
- additionalMetaSchemas: undefined,
- });
- });
- });
-
- describe('when props.formData equals the default values', () => {
- beforeEach(() => {
- formData = {
- count: 789,
- };
- createComponent();
- });
-
- it('should not call props.onChange', () => {
- expect(onChangeProp).not.toHaveBeenCalled();
- });
- });
- });
-
- describe('Option idPrefix', function () {
- it('should change the rendered ids', function () {
- const schema = {
- type: 'object',
- title: 'root object',
- required: ['foo'],
- properties: {
- count: {
- type: 'number',
- },
- },
- };
- const comp = renderIntoDocument();
- const node = findDOMNode(comp);
- const inputs = node.querySelectorAll('input');
- const ids = [];
- for (let i = 0, len = inputs.length; i < len; i++) {
- const input = inputs[i];
- ids.push(input.getAttribute('id'));
- }
- expect(ids).toStrictEqual(['rjsf_count']);
- expect(node.querySelector('fieldset').id).toBe('rjsf');
- });
- });
-
- describe('Changing idPrefix', function () {
- it('should work with simple example', function () {
- const schema = {
- type: 'object',
- title: 'root object',
- required: ['foo'],
- properties: {
- count: {
- type: 'number',
- },
- },
- };
- const comp = renderIntoDocument();
- const node = findDOMNode(comp);
- const inputs = node.querySelectorAll('input');
- const ids = [];
- for (let i = 0, len = inputs.length; i < len; i++) {
- const input = inputs[i];
- ids.push(input.getAttribute('id'));
- }
- expect(ids).toStrictEqual(['rjsf_count']);
- expect(node.querySelector('fieldset').id).toBe('rjsf');
- });
-
- it('should work with oneOf', function () {
- const schema = {
- $schema: 'http://json-schema.org/draft-06/schema#',
- type: 'object',
- properties: {
- connector: {
- type: 'string',
- enum: ['aws', 'gcp'],
- title: 'Provider',
- default: 'aws',
- },
- },
- dependencies: {
- connector: {
- oneOf: [
- {
- type: 'object',
- properties: {
- connector: {
- type: 'string',
- enum: ['aws'],
- },
- key_aws: {
- type: 'string',
- },
- },
- },
- {
- type: 'object',
- properties: {
- connector: {
- type: 'string',
- enum: ['gcp'],
- },
- key_gcp: {
- type: 'string',
- },
- },
- },
- ],
- },
- },
- };
-
- const comp = renderIntoDocument();
- const node = findDOMNode(comp);
- const inputs = node.querySelectorAll('input');
- const ids = [];
- for (let i = 0, len = inputs.length; i < len; i++) {
- const input = inputs[i];
- ids.push(input.getAttribute('id'));
- }
- expect(ids).toStrictEqual(['rjsf_key_aws']);
- });
- });
-
- describe('Custom field template', () => {
- const schema = {
- type: 'object',
- title: 'root object',
- required: ['foo'],
- properties: {
- foo: {
- type: 'string',
- description: 'this is description',
- minLength: 32,
- },
- },
- };
-
- const uiSchema = {
- foo: {
- 'ui:help': 'this is help',
- },
- };
-
- const formData = { foo: 'invalid' };
-
- function FieldTemplate(props) {
- const {
- id,
- classNames,
- label,
- help,
- rawHelp,
- required,
- description,
- rawDescription,
- errors,
- rawErrors,
- children,
- } = props;
- return (
-
-
- {label}
- {required ? '*' : null}
-
- {description}
- {children}
- {errors}
- {help}
-
{`${rawHelp} rendered from the raw format`}
-
{`${rawDescription} rendered from the raw format`}
- {rawErrors ? (
-
- {rawErrors.map((error, i) => (
-
- {error}
-
- ))}
-
- ) : null}
-
- );
- }
-
- let node;
-
- beforeEach(() => {
- node = createFormComponent({
- schema,
- uiSchema,
- formData,
- FieldTemplate,
- liveValidate: true,
- }).node;
- });
-
- it('should use the provided field template', () => {
- expect(node.querySelector('.my-template')).not.toBeNull();
- });
-
- it('should use the provided template for labels', () => {
- expect(node.querySelector('.my-template > label')).toHaveTextContent('root object');
- expect(node.querySelector('.my-template .field-string > label')).toHaveTextContent('foo*');
- });
-
- it('should pass description as the provided React element', () => {
- expect(node.querySelector('#root_foo__description')).toHaveTextContent('this is description');
- });
-
- it('should pass rawDescription as a string', () => {
- expect(node.querySelector('.raw-description')).toHaveTextContent(
- 'this is description rendered from the raw format'
- );
- });
-
- it('should pass errors as the provided React component', () => {
- expect(node.querySelectorAll('.error-detail li')).toHaveLength(1);
- });
-
- it('should pass rawErrors as an array of strings', () => {
- expect(node.querySelectorAll('.raw-error')).toHaveLength(1);
- });
-
- it('should pass help as a the provided React element', () => {
- expect(node.querySelector('.help-block')).toHaveTextContent('this is help');
- });
-
- it('should pass rawHelp as a string', () => {
- expect(node.querySelector('.raw-help')).toHaveTextContent('this is help rendered from the raw format');
- });
- });
-
- describe('Schema definitions', () => {
- it('should use a single schema definition reference', () => {
- const schema = {
- definitions: {
- testdef: { type: 'string' },
- },
- $ref: '#/definitions/testdef',
- };
-
- const { node } = createFormComponent({ schema });
-
- expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
- });
-
- it('should recursively handle refer multiple schema definition references', () => {
- const schema = {
- definitions: {
- testdef: { type: 'string' },
- },
- type: 'object',
- properties: {
- foo: { $ref: '#/definitions/testdef' },
- bar: { $ref: '#/definitions/testdef' },
- },
- };
-
- const { node } = createFormComponent({ schema });
-
- expect(node.querySelectorAll('input[type=text]')).toHaveLength(2);
- });
-
- it('should handle deeply referenced schema definitions', () => {
- const schema = {
- definitions: {
- testdef: { type: 'string' },
- },
- type: 'object',
- properties: {
- foo: {
- type: 'object',
- properties: {
- bar: { $ref: '#/definitions/testdef' },
- },
- },
- },
- };
-
- const { node } = createFormComponent({ schema });
-
- expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
- });
-
- it('should handle references to deep schema definitions', () => {
- const schema = {
- definitions: {
- testdef: {
- type: 'object',
- properties: {
- bar: { type: 'string' },
- },
- },
- },
- type: 'object',
- properties: {
- foo: { $ref: '#/definitions/testdef/properties/bar' },
- },
- };
-
- const { node } = createFormComponent({ schema });
-
- expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
- });
-
- it('should handle referenced definitions for array items', () => {
- const schema = {
- definitions: {
- testdef: { type: 'string' },
- },
- type: 'object',
- properties: {
- foo: {
- type: 'array',
- items: { $ref: '#/definitions/testdef' },
- },
- },
- };
-
- const { node } = createFormComponent({
- schema,
- formData: {
- foo: ['blah'],
- },
- });
-
- expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
- });
-
- it('should raise for non-existent definitions referenced', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { $ref: '#/definitions/nonexistent' },
- },
- };
-
- expect(() => createFormComponent({ schema })).toThrow(/#\/definitions\/nonexistent/);
- });
-
- it('should propagate referenced definition defaults', () => {
- const schema = {
- definitions: {
- testdef: { type: 'string', default: 'hello' },
- },
- $ref: '#/definitions/testdef',
- };
-
- const { node } = createFormComponent({ schema });
-
- expect(node.querySelector('input[type=text]').value).toBe('hello');
- });
-
- it('should propagate nested referenced definition defaults', () => {
- const schema = {
- definitions: {
- testdef: { type: 'string', default: 'hello' },
- },
- type: 'object',
- properties: {
- foo: { $ref: '#/definitions/testdef' },
- },
- };
-
- const { node } = createFormComponent({ schema });
-
- expect(node.querySelector('input[type=text]').value).toBe('hello');
- });
-
- it('should propagate referenced definition defaults for array items', () => {
- const schema = {
- definitions: {
- testdef: { type: 'string', default: 'hello' },
- },
- type: 'array',
- items: {
- $ref: '#/definitions/testdef',
- },
- };
-
- const { node } = createFormComponent({ schema });
-
- Simulate.click(node.querySelector('.array-item-add button'));
-
- expect(node.querySelector('input[type=text]').value).toBe('hello');
- });
-
- it('should propagate referenced definition defaults in objects with additionalProperties', () => {
- const schema = {
- definitions: {
- testdef: { type: 'string' },
- },
- type: 'object',
- additionalProperties: {
- $ref: '#/definitions/testdef',
- },
- };
-
- const { node } = createFormComponent({ schema });
-
- Simulate.click(node.querySelector('.btn-add'));
-
- expect(node.querySelector('input[type=text]').value).toBe('newKey');
- });
-
- it('should propagate referenced definition defaults in objects with additionalProperties that have a type present', () => {
- // Though `additionalProperties` has a `type` present here, it also has a `$ref` so that
- // referenced schema should override it.
- const schema = {
- definitions: {
- testdef: { type: 'number' },
- },
- type: 'object',
- additionalProperties: {
- type: 'string',
- $ref: '#/definitions/testdef',
- },
- };
-
- const { node } = createFormComponent({ schema });
-
- Simulate.click(node.querySelector('.btn-add'));
-
- expect(node.querySelector('input[type=number]').value).toBe('0');
- });
-
- it('should follow recursive references', () => {
- const schema = {
- definitions: {
- bar: { $ref: '#/definitions/qux' },
- qux: { type: 'string' },
- },
- type: 'object',
- required: ['foo'],
- properties: {
- foo: { $ref: '#/definitions/bar' },
- },
- };
- const { node } = createFormComponent({ schema });
-
- expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
- });
-
- it('should follow multiple recursive references', () => {
- const schema = {
- definitions: {
- bar: { $ref: '#/definitions/bar2' },
- bar2: { $ref: '#/definitions/qux' },
- qux: { type: 'string' },
- },
- type: 'object',
- required: ['foo'],
- properties: {
- foo: { $ref: '#/definitions/bar' },
- },
- };
- const { node } = createFormComponent({ schema });
-
- expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
- });
-
- it('should priorize definition over schema type property', () => {
- // Refs bug #140
- const schema = {
- type: 'object',
- properties: {
- name: { type: 'string' },
- childObj: {
- type: 'object',
- $ref: '#/definitions/childObj',
- },
- },
- definitions: {
- childObj: {
- type: 'object',
- properties: {
- otherName: { type: 'string' },
- },
- },
- },
- };
-
- const { node } = createFormComponent({ schema });
-
- expect(node.querySelectorAll('input[type=text]')).toHaveLength(2);
- });
-
- it('should priorize local properties over definition ones', () => {
- // Refs bug #140
- const schema = {
- type: 'object',
- properties: {
- foo: {
- title: 'custom title',
- $ref: '#/definitions/objectDef',
- },
- },
- definitions: {
- objectDef: {
- type: 'object',
- title: 'definition title',
- properties: {
- field: { type: 'string' },
- },
- },
- },
- };
-
- const { node } = createFormComponent({ schema });
-
- expect(node.querySelector('legend')).toHaveTextContent('custom title');
- });
-
- it('should propagate and handle a resolved schema definition', () => {
- const schema = {
- definitions: {
- enumDef: { type: 'string', enum: ['a', 'b'] },
- },
- type: 'object',
- properties: {
- name: { $ref: '#/definitions/enumDef' },
- },
- };
-
- const { node } = createFormComponent({ schema });
-
- expect(node.querySelectorAll('option')).toHaveLength(3);
- });
- });
-
- describe('Default value handling on clear', () => {
- const schema = {
- type: 'string',
- default: 'foo',
- };
-
- it('should not set default when a text field is cleared', () => {
- const { node } = createFormComponent({ schema, formData: 'bar' });
-
- Simulate.change(node.querySelector('input'), {
- target: { value: '' },
- });
-
- expect(node.querySelector('input').value).toBe('');
- });
- });
-
- describe('Defaults array items default propagation', () => {
- const schema = {
- type: 'object',
- title: 'lvl 1 obj',
- properties: {
- object: {
- type: 'object',
- title: 'lvl 2 obj',
- properties: {
- array: {
- type: 'array',
- items: {
- type: 'object',
- title: 'lvl 3 obj',
- properties: {
- bool: {
- type: 'boolean',
- default: true,
- },
- },
- },
- },
- },
- },
- },
- };
-
- it('should propagate deeply nested defaults to submit handler', () => {
- const { node, onSubmit } = createFormComponent({ schema });
-
- Simulate.click(node.querySelector('.array-item-add button'));
- Simulate.submit(node);
-
- expect(onSubmit).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: {
- object: {
- array: [
- {
- bool: true,
- },
- ],
- },
- },
- }),
- expect.anything()
- );
- });
- });
-
- describe('Submit handler', () => {
- it('should call provided submit handler with form state', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- },
- };
- const formData = {
- foo: 'bar',
- };
- const onSubmit = jest.fn();
- const event = { type: 'submit' };
- const { node } = createFormComponent({
- schema,
- formData,
- onSubmit,
- });
-
- Simulate.submit(node, event);
- expect(onSubmit).toHaveBeenLastCalledWith(
- expect.objectContaining({ formData, schema }),
- expect.objectContaining(event)
- );
- });
-
- it('should not call provided submit handler on validation errors', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: {
- type: 'string',
- minLength: 1,
- },
- },
- };
- const formData = {
- foo: '',
- };
- const onSubmit = jest.fn();
- const onError = jest.fn();
- const { node } = createFormComponent({
- schema,
- formData,
- onSubmit,
- onError,
- });
-
- Simulate.submit(node);
-
- expect(onSubmit).not.toHaveBeenCalled();
- });
- });
-
- describe('Change handler', () => {
- it('should call provided change handler on form state change', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: {
- type: 'string',
- },
- },
- };
- const formData = {
- foo: '',
- };
- const onChange = jest.fn();
- const { node } = createFormComponent({
- schema,
- formData,
- onChange,
- });
-
- Simulate.change(node.querySelector('[type=text]'), {
- target: { value: 'new' },
- });
-
- expect(onChange).toHaveBeenCalledWith(
- expect.objectContaining({
- formData: {
- foo: 'new',
- },
- })
- );
- });
- });
-
- describe('Blur handler', () => {
- it('should call provided blur handler on form input blur event', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: {
- type: 'string',
- },
- },
- };
- const formData = {
- foo: '',
- };
- const onBlur = jest.fn();
- const { node } = createFormComponent({ schema, formData, onBlur });
-
- const input = node.querySelector('[type=text]');
- Simulate.blur(input, {
- target: { value: 'new' },
- });
-
- expect(onBlur).toHaveBeenCalledWith(input.id, 'new');
- });
- });
-
- describe('Focus handler', () => {
- it('should call provided focus handler on form input focus event', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: {
- type: 'string',
- },
- },
- };
- const formData = {
- foo: '',
- };
- const onFocus = jest.fn();
- const { node } = createFormComponent({ schema, formData, onFocus });
-
- const input = node.querySelector('[type=text]');
- Simulate.focus(input, {
- target: { value: 'new' },
- });
-
- expect(onFocus).toHaveBeenCalledWith(input.id, 'new');
- });
- });
-
- describe('Error handler', () => {
- it('should call provided error handler on validation errors', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: {
- type: 'string',
- minLength: 1,
- },
- },
- };
- const formData = {
- foo: '',
- };
- const onError = jest.fn();
- const { node } = createFormComponent({ schema, formData, onError });
-
- Simulate.submit(node);
-
- expect(onError).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('Schema and external formData updates', () => {
- let comp;
- let onChangeProp;
- let formProps;
-
- beforeEach(() => {
- onChangeProp = jest.fn();
- formProps = {
- schema: {
- type: 'string',
- default: 'foobar',
- },
- formData: 'some value',
- onChange: onChangeProp,
- };
- comp = createFormComponent(formProps).comp;
- });
-
- describe('when the form data is set to null', () => {
- beforeEach(() =>
- setProps(comp, {
- ...formProps,
- formData: null,
- })
- );
-
- it('should call onChange', () => {
- expect(onChangeProp).toHaveBeenCalledTimes(1);
- expect(onChangeProp).toHaveBeenCalledWith({
- additionalMetaSchemas: undefined,
- edit: true,
- errorSchema: {},
- errors: [],
- formData: 'foobar',
- idSchema: { $id: 'root' },
- schema: formProps.schema,
- uiSchema: {},
- });
- });
- });
-
- describe('when the schema default is changed but formData is not changed', () => {
- const newSchema = {
- type: 'string',
- default: 'the new default',
- };
-
- beforeEach(() =>
- setProps(comp, {
- ...formProps,
- schema: newSchema,
- formData: 'some value',
- })
- );
-
- it('should not call onChange', () => {
- expect(onChangeProp).not.toHaveBeenCalled();
- });
- });
-
- describe('when the schema default is changed and formData is changed', () => {
- const newSchema = {
- type: 'string',
- default: 'the new default',
- };
-
- beforeEach(() =>
- setProps(comp, {
- ...formProps,
- schema: newSchema,
- formData: 'something else',
- })
- );
-
- it('should not call onChange', () => {
- expect(onChangeProp).not.toHaveBeenCalled();
- });
- });
-
- describe('when the schema default is changed and formData is nulled', () => {
- const newSchema = {
- type: 'string',
- default: 'the new default',
- };
-
- beforeEach(() =>
- setProps(comp, {
- ...formProps,
- schema: newSchema,
- formData: null,
- })
- );
-
- it('should call onChange', () => {
- expect(onChangeProp).toHaveBeenCalledTimes(1);
- expect(onChangeProp).toHaveBeenCalledWith(
- expect.objectContaining({
- schema: newSchema,
- formData: 'the new default',
- })
- );
- });
- });
-
- describe('when the onChange prop sets formData to a falsey value', () => {
- class TestForm extends React.Component {
- constructor() {
- super();
-
- this.state = {
- formData: {},
- };
- }
-
- onChange = () => {
- this.setState({ formData: this.props.falseyValue });
- };
-
- render() {
- const schema = {
- type: 'object',
- properties: {
- value: {
- type: 'string',
- },
- },
- };
- return ;
- }
- }
-
- it.each([[0], [false], [null], [undefined], [NaN]])(
- 'should not crash due to "Maximum call stack size exceeded..." with `%s`"',
- falsyValue => {
- // It is expected that this will throw an error due to non-matching propTypes,
- // so the error message needs to be inspected
- expect(() => {
- createComponent(TestForm, { falsyValue });
- }).not.toThrow('Maximum call stack size exceeded');
- }
- );
- });
- });
-
- describe('External formData updates', () => {
- describe('root level', () => {
- const formProps = {
- schema: { type: 'string' },
- liveValidate: true,
- };
-
- it('should call submit handler with new formData prop value', () => {
- const { comp, node, onSubmit } = createFormComponent(formProps);
-
- setProps(comp, {
- ...formProps,
- onSubmit,
- formData: 'yo',
- });
- submitForm(node);
- expect(onSubmit).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: 'yo',
- }),
- expect.anything()
- );
- });
-
- it('should validate formData when the schema is updated', () => {
- const { comp, node, onError } = createFormComponent(formProps);
-
- setProps(comp, {
- ...formProps,
- onError,
- formData: 'yo',
- schema: { type: 'number' },
- });
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should be number',
- name: 'type',
- params: { type: 'number' },
- property: '',
- schemaPath: '#/type',
- stack: 'should be number',
- },
- ])
- );
- });
- });
-
- describe('object level', () => {
- it('should call submit handler with new formData prop value', () => {
- const formProps = {
- schema: { type: 'object', properties: { foo: { type: 'string' } } },
- };
- const { comp, onSubmit, node } = createFormComponent(formProps);
-
- setProps(comp, {
- ...formProps,
- onSubmit,
- formData: { foo: 'yo' },
- });
-
- submitForm(node);
- expect(onSubmit).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: { foo: 'yo' },
- }),
- expect.anything()
- );
- });
- });
-
- describe('array level', () => {
- it('should call submit handler with new formData prop value', () => {
- const schema = {
- type: 'array',
- items: {
- type: 'string',
- },
- };
- const { comp, node, onSubmit } = createFormComponent({ schema });
-
- setProps(comp, { schema, onSubmit, formData: ['yo'] });
-
- submitForm(node);
- expect(onSubmit).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: ['yo'],
- }),
- expect.anything()
- );
- });
- });
- });
-
- describe('Internal formData updates', () => {
- it('root', () => {
- const formProps = {
- schema: { type: 'string' },
- liveValidate: true,
- };
- const { node, onChange } = createFormComponent(formProps);
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'yo' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: 'yo',
- })
- );
- });
-
- it('object', () => {
- const { node, onChange } = createFormComponent({
- schema: {
- type: 'object',
- properties: {
- foo: {
- type: 'string',
- },
- },
- },
- });
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'yo' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: { foo: 'yo' },
- })
- );
- });
-
- it('array of strings', () => {
- const schema = {
- type: 'array',
- items: {
- type: 'string',
- },
- };
- const { node, onChange } = createFormComponent({ schema });
-
- Simulate.click(node.querySelector('.array-item-add button'));
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'yo' },
- });
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: ['yo'],
- })
- );
- });
-
- it('array of objects', () => {
- const schema = {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- name: { type: 'string' },
- },
- },
- };
- const { node, onChange } = createFormComponent({ schema });
-
- Simulate.click(node.querySelector('.array-item-add button'));
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'yo' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: [{ name: 'yo' }],
- })
- );
- });
-
- it('dependency with array of objects', () => {
- const schema = {
- definitions: {},
- type: 'object',
- properties: {
- show: {
- type: 'boolean',
- },
- },
- dependencies: {
- show: {
- oneOf: [
- {
- properties: {
- show: {
- const: true,
- },
- participants: {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- },
- },
- },
- },
- },
- },
- ],
- },
- },
- };
- const { node, onChange } = createFormComponent({ schema });
-
- Simulate.change(node.querySelector('[type=checkbox]'), {
- target: { checked: true },
- });
-
- Simulate.click(node.querySelector('.array-item-add button'));
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'yo' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: {
- show: true,
- participants: [{ name: 'yo' }],
- },
- })
- );
- });
- });
-
- describe('Error contextualization', () => {
- describe('on form state updated', () => {
- const schema = {
- type: 'string',
- minLength: 8,
- };
-
- describe('Lazy validation', () => {
- it('should not update the errorSchema when the formData changes', () => {
- const { node, onChange } = createFormComponent({ schema });
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'short' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.not.objectContaining({
- errorSchema: undefined,
- })
- );
- });
-
- it('should not denote an error in the field', () => {
- const { node } = createFormComponent({ schema });
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'short' },
- });
-
- expect(node.querySelectorAll('.field-error')).toHaveLength(0);
- });
-
- it("should clean contextualized errors up when they're fixed", () => {
- const altSchema = {
- type: 'object',
- properties: {
- field1: { type: 'string', minLength: 8 },
- field2: { type: 'string', minLength: 8 },
- },
- };
- const { node } = createFormComponent({
- schema: altSchema,
- formData: {
- field1: 'short',
- field2: 'short',
- },
- });
-
- Simulate.submit(node);
-
- // Fix the first field
- Simulate.change(node.querySelectorAll('input[type=text]')[0], {
- target: { value: 'fixed error' },
- });
- Simulate.submit(node);
-
- expect(node.querySelectorAll('.field-error')).toHaveLength(1);
-
- // Fix the second field
- Simulate.change(node.querySelectorAll('input[type=text]')[1], {
- target: { value: 'fixed error too' },
- });
- Simulate.submit(node);
-
- // No error remaining, shouldn't throw.
- Simulate.submit(node);
-
- expect(node.querySelectorAll('.field-error')).toHaveLength(0);
- });
- });
-
- describe('Live validation', () => {
- it('should update the errorSchema when the formData changes', () => {
- const { node, onChange } = createFormComponent({
- schema,
- liveValidate: true,
- });
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'short' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: {
- __errors: ['should NOT be shorter than 8 characters'],
- },
- })
- );
- });
-
- it('should denote the new error in the field', () => {
- const { node } = createFormComponent({
- schema,
- liveValidate: true,
- });
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'short' },
- });
-
- expect(node.querySelectorAll('.field-error')).toHaveLength(1);
- expect(node.querySelector('.field-string .error-detail')).toHaveTextContent(
- 'should NOT be shorter than 8 characters'
- );
- });
- });
-
- describe('Disable validation onChange event', () => {
- it('should not update errorSchema when the formData changes', () => {
- const { node, onChange } = createFormComponent({
- schema,
- noValidate: true,
- liveValidate: true,
- });
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'short' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.not.objectContaining({
- errorSchema: undefined,
- })
- );
- });
- });
-
- describe('Disable validation onSubmit event', () => {
- it('should not update errorSchema when the formData changes', () => {
- const { node, onSubmit } = createFormComponent({
- schema,
- noValidate: true,
- });
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'short' },
- });
- Simulate.submit(node);
-
- expect(onSubmit).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: {},
- }),
- expect.anything()
- );
- });
- });
- });
-
- describe('on form submitted', () => {
- const schema = {
- type: 'string',
- minLength: 8,
- };
-
- it('should call the onError handler', () => {
- const onError = jest.fn();
- const { node } = createFormComponent({ schema, onError });
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'short' },
- });
- Simulate.submit(node);
-
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- expect.objectContaining({
- message: expect.stringContaining('should NOT be shorter than 8 characters'),
- }),
- ])
- );
- });
-
- it('should reset errors and errorSchema state to initial state after correction and resubmission', () => {
- const { node, onError } = createFormComponent({
- schema,
- });
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'short' },
- });
- Simulate.submit(node);
-
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should NOT be shorter than 8 characters',
- name: 'minLength',
- params: { limit: 8 },
- property: '',
- schemaPath: '#/minLength',
- stack: 'should NOT be shorter than 8 characters',
- },
- ])
- );
- expect(onError).toHaveBeenCalledTimes(1);
- onError.mockClear();
-
- Simulate.change(node.querySelector('input[type=text]'), {
- target: { value: 'long enough' },
- });
- Simulate.submit(node);
- expect(onError).not.toHaveBeenCalled();
- });
- });
-
- describe('root level', () => {
- const formProps = {
- liveValidate: true,
- schema: {
- type: 'string',
- minLength: 8,
- },
- formData: 'short',
- };
-
- it('should reflect the contextualized error in state', () => {
- const { node, onError } = createFormComponent(formProps);
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should NOT be shorter than 8 characters',
- name: 'minLength',
- params: { limit: 8 },
- property: '',
- schemaPath: '#/minLength',
- stack: 'should NOT be shorter than 8 characters',
- },
- ])
- );
- });
-
- it('should denote the error in the field', () => {
- const { node } = createFormComponent(formProps);
-
- expect(node.querySelectorAll('.field-error')).toHaveLength(1);
- expect(node.querySelector('.field-string .error-detail')).toHaveTextContent(
- 'should NOT be shorter than 8 characters'
- );
- });
- });
-
- describe('root level with multiple errors', () => {
- const formProps = {
- liveValidate: true,
- schema: {
- type: 'string',
- minLength: 8,
- pattern: 'd+',
- },
- formData: 'short',
- };
-
- it('should reflect the contextualized error in state', () => {
- const { node, onError } = createFormComponent(formProps);
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should NOT be shorter than 8 characters',
- name: 'minLength',
- params: { limit: 8 },
- property: '',
- schemaPath: '#/minLength',
- stack: 'should NOT be shorter than 8 characters',
- },
- {
- message: 'should match pattern "d+"',
- name: 'pattern',
- params: { pattern: 'd+' },
- property: '',
- schemaPath: '#/pattern',
- stack: 'should match pattern "d+"',
- },
- ])
- );
- });
-
- it('should denote the error in the field', () => {
- const { node } = createFormComponent(formProps);
-
- const liNodes = node.querySelectorAll('.field-string .error-detail li');
- const errors = [].map.call(liNodes, li => li.textContent);
-
- expect(errors).toStrictEqual(['should NOT be shorter than 8 characters', 'should match pattern "d+"']);
- });
- });
-
- describe('nested field level', () => {
- const schema = {
- type: 'object',
- properties: {
- level1: {
- type: 'object',
- properties: {
- level2: {
- type: 'string',
- minLength: 8,
- },
- },
- },
- },
- };
-
- const formProps = {
- schema,
- liveValidate: true,
- formData: {
- level1: {
- level2: 'short',
- },
- },
- };
-
- it('should reflect the contextualized error in state', () => {
- const { node, onError } = createFormComponent(formProps);
-
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should NOT be shorter than 8 characters',
- name: 'minLength',
- params: { limit: 8 },
- property: '.level1.level2',
- schemaPath: '#/properties/level1/properties/level2/minLength',
- stack: '.level1.level2 should NOT be shorter than 8 characters',
- },
- ])
- );
- });
-
- it('should denote the error in the field', () => {
- const { node } = createFormComponent(formProps);
- const errorDetail = node.querySelector('.field-object .field-string .error-detail');
-
- expect(node.querySelectorAll('.field-error')).toHaveLength(1);
- expect(errorDetail).toHaveTextContent('should NOT be shorter than 8 characters');
- });
- });
-
- describe('array indices', () => {
- const schema = {
- type: 'array',
- items: {
- type: 'string',
- minLength: 4,
- },
- };
-
- const formProps = {
- schema,
- liveValidate: true,
- formData: ['good', 'bad', 'good'],
- };
-
- it('should contextualize the error for array indices', () => {
- const { node, onError } = createFormComponent(formProps);
-
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should NOT be shorter than 4 characters',
- name: 'minLength',
- params: { limit: 4 },
- property: '[1]',
- schemaPath: '#/items/minLength',
- stack: '[1] should NOT be shorter than 4 characters',
- },
- ])
- );
- });
-
- it('should denote the error in the item field in error', () => {
- const { node } = createFormComponent(formProps);
- const fieldNodes = node.querySelectorAll('.field-string');
-
- const liNodes = fieldNodes[1].querySelectorAll('.field-string .error-detail li');
- const errors = [].map.call(liNodes, li => li.textContent);
-
- expect(fieldNodes[1]).toHaveClass('field-error');
- expect(errors).toStrictEqual(['should NOT be shorter than 4 characters']);
- });
-
- it('should not denote errors on non impacted fields', () => {
- const { node } = createFormComponent(formProps);
- const fieldNodes = node.querySelectorAll('.field-string');
-
- expect(fieldNodes[0]).not.toHaveClass('field-error');
- expect(fieldNodes[2]).not.toHaveClass('field-error');
- });
- });
-
- describe('nested array indices', () => {
- const schema = {
- type: 'object',
- properties: {
- level1: {
- type: 'array',
- items: {
- type: 'string',
- minLength: 4,
- },
- },
- },
- };
-
- const formProps = { schema, liveValidate: true };
-
- it('should contextualize the error for nested array indices', () => {
- const { node, onError } = createFormComponent({
- ...formProps,
- formData: {
- level1: ['good', 'bad', 'good', 'bad'],
- },
- });
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should NOT be shorter than 4 characters',
- name: 'minLength',
- params: { limit: 4 },
- property: '.level1[1]',
- schemaPath: '#/properties/level1/items/minLength',
- stack: '.level1[1] should NOT be shorter than 4 characters',
- },
- {
- message: 'should NOT be shorter than 4 characters',
- name: 'minLength',
- params: { limit: 4 },
- property: '.level1[3]',
- schemaPath: '#/properties/level1/items/minLength',
- stack: '.level1[3] should NOT be shorter than 4 characters',
- },
- ])
- );
- });
-
- it('should denote the error in the nested item field in error', () => {
- const { node } = createFormComponent({
- ...formProps,
- formData: {
- level1: ['good', 'bad', 'good'],
- },
- });
-
- const liNodes = node.querySelectorAll('.field-string .error-detail li');
- const errors = [].map.call(liNodes, li => li.textContent);
-
- expect(errors).toStrictEqual(['should NOT be shorter than 4 characters']);
- });
- });
-
- describe('nested arrays', () => {
- const schema = {
- type: 'object',
- properties: {
- outer: {
- type: 'array',
- items: {
- type: 'array',
- items: {
- type: 'string',
- minLength: 4,
- },
- },
- },
- },
- };
-
- const formData = {
- outer: [
- ['good', 'bad'],
- ['bad', 'good'],
- ],
- };
-
- const formProps = { schema, formData, liveValidate: true };
-
- it('should contextualize the error for nested array indices', () => {
- const { node, onError } = createFormComponent(formProps);
-
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should NOT be shorter than 4 characters',
- name: 'minLength',
- params: { limit: 4 },
- property: '.outer[0][1]',
- schemaPath: '#/properties/outer/items/items/minLength',
- stack: '.outer[0][1] should NOT be shorter than 4 characters',
- },
- {
- message: 'should NOT be shorter than 4 characters',
- name: 'minLength',
- params: { limit: 4 },
- property: '.outer[1][0]',
- schemaPath: '#/properties/outer/items/items/minLength',
- stack: '.outer[1][0] should NOT be shorter than 4 characters',
- },
- ])
- );
- });
-
- it('should denote the error in the nested item field in error', () => {
- const { node } = createFormComponent(formProps);
- const fields = node.querySelectorAll('.field-string');
- const errors = [].map.call(fields, field => {
- const li = field.querySelector('.error-detail li');
- return li && li.textContent;
- });
-
- expect(errors).toStrictEqual([
- null,
- 'should NOT be shorter than 4 characters',
- 'should NOT be shorter than 4 characters',
- null,
- ]);
- });
- });
-
- describe('array nested items', () => {
- const schema = {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- foo: {
- type: 'string',
- minLength: 4,
- },
- },
- },
- };
-
- const formProps = {
- schema,
- liveValidate: true,
- formData: [{ foo: 'good' }, { foo: 'bad' }, { foo: 'good' }],
- };
+beforeAll(() => {
+ createFormComponentFn = props => createFormComponent({ ...props });
+});
- it('should contextualize the error for array nested items', () => {
- const { node, onError } = createFormComponent(formProps);
+describe('Empty schema', () => {
+ it('should render a form tag', () => {
+ const { node } = createFormComponentFn({ schema: {} });
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should NOT be shorter than 4 characters',
- name: 'minLength',
- params: { limit: 4 },
- property: '[1].foo',
- schemaPath: '#/items/properties/foo/minLength',
- stack: '[1].foo should NOT be shorter than 4 characters',
- },
- ])
- );
- });
+ expect(node.tagName).toBe('FORM');
+ });
- it('should denote the error in the array nested item', () => {
- const { node } = createFormComponent(formProps);
- const fieldNodes = node.querySelectorAll('.field-string');
+ it('should render a submit button', () => {
+ const { node } = createFormComponent({ schema: {} });
- const liNodes = fieldNodes[1].querySelectorAll('.field-string .error-detail li');
- const errors = [].map.call(liNodes, li => li.textContent);
+ expect(node.querySelectorAll('button[type=submit]')).toHaveLength(1);
+ });
- expect(fieldNodes[1]).toHaveClass('field-error');
- expect(errors).toStrictEqual(['should NOT be shorter than 4 characters']);
- });
- });
+ it('should render children buttons', () => {
+ const props = { schema: {} };
+ const comp = renderIntoDocument(
+
+ );
+ const node = findDOMNode(comp);
+ expect(node.querySelectorAll('button[type=submit]')).toHaveLength(2);
+ });
- describe('schema dependencies', () => {
- const schema = {
+ it("should render an UnsupportedField error if schema isn't object", () => {
+ const props = {
+ schema: {
type: 'object',
+ title: 'object',
properties: {
- branch: {
- type: 'number',
- enum: [1, 2, 3],
- default: 1,
+ firstName: 'some mame',
+ address: {
+ $ref: '#/definitions/address',
},
},
- required: ['branch'],
- dependencies: {
- branch: {
- oneOf: [
- {
- properties: {
- branch: {
- enum: [1],
- },
- field1: {
- type: 'number',
- },
- },
- required: ['field1'],
- },
- {
- properties: {
- branch: {
- enum: [2],
- },
- field1: {
- type: 'number',
- },
- field2: {
- type: 'number',
- },
- },
- required: ['field1', 'field2'],
- },
- ],
+ definitions: {
+ address: {
+ street: 'some street',
},
},
- };
+ },
+ };
+ const comp = renderIntoDocument(
+
+ );
+ const node = findDOMNode(comp);
+ expect(node.querySelector('.unsupported-field')).toHaveTextContent('Unknown field type undefined');
+ });
+});
- it('should only show error for property in selected branch', () => {
- const { node, onChange } = createFormComponent({
- schema,
- liveValidate: true,
- });
+describe('on component creation', () => {
+ let onChangeProp;
+ let formData;
+ let schema;
+
+ function createComponent() {
+ renderIntoDocument(
+
+ );
+ }
+
+ beforeEach(() => {
+ onChangeProp = jest.fn();
+ schema = {
+ type: 'object',
+ title: 'root object',
+ required: ['count'],
+ properties: {
+ count: {
+ type: 'number',
+ default: 789,
+ },
+ },
+ };
+ });
- Simulate.change(node.querySelector('input[type=number]'), {
- target: { value: 'not a number' },
- });
+ describe('when props.formData does not equal the default values', () => {
+ beforeEach(() => {
+ formData = {
+ foo: 123,
+ };
+ createComponent();
+ });
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: { field1: { __errors: ['should be number'] } },
- })
- );
+ it('should call props.onChange with current state', () => {
+ expect(onChangeProp).toHaveBeenCalledTimes(1);
+ expect(onChangeProp).toHaveBeenCalledWith({
+ formData: { ...formData, count: 789 },
+ schema,
+ edit: true,
+ uiSchema: {},
+ idSchema: { $id: 'root', count: { $id: 'root_count' } },
});
+ });
+ });
- it('should only show errors for properties in selected branch', () => {
- const { node, onChange } = createFormComponent({
- schema,
- liveValidate: true,
- formData: { branch: 2 },
- });
-
- Simulate.change(node.querySelector('input[type=number]'), {
- target: { value: 'not a number' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: {
- field1: {
- __errors: ['should be number'],
- },
- field2: {
- __errors: ['is a required property'],
- },
- },
- })
- );
- });
+ describe('when props.formData equals the default values', () => {
+ beforeEach(() => {
+ formData = {
+ count: 789,
+ };
+ createComponent();
+ });
- it('should not show any errors when branch is empty', () => {
- const { node, onChange } = createFormComponent({
- schema,
- liveValidate: true,
- formData: { branch: 3 },
- });
-
- Simulate.change(node.querySelector('select'), {
- target: { value: 3 },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: {},
- })
- );
- });
+ it('should not call props.onChange', () => {
+ expect(onChangeProp).not.toHaveBeenCalled();
});
});
+});
- describe('Schema and formData updates', () => {
- // https://github.com/mozilla-services/react-jsonschema-form/issues/231
+describe('Option idPrefix', function () {
+ it('should change the rendered ids', function () {
const schema = {
type: 'object',
+ title: 'root object',
+ required: ['foo'],
properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
+ count: {
+ type: 'number',
+ },
},
};
+ const comp = renderIntoDocument();
+ const node = findDOMNode(comp);
+ const inputs = node.querySelectorAll('input');
+ const ids = [];
+ for (let i = 0, len = inputs.length; i < len; i++) {
+ const input = inputs[i];
+ ids.push(input.getAttribute('id'));
+ }
+ expect(ids).toStrictEqual(['rjsf_count']);
+ expect(node.querySelector('fieldset').id).toBe('rjsf');
+ });
+});
- it('should replace state when props remove formData keys', () => {
- const formData = { foo: 'foo', bar: 'bar' };
- const { comp, node, onChange } = createFormComponent({
- schema,
- formData,
- });
-
- setProps(comp, {
- onChange,
- schema: {
- type: 'object',
- properties: {
- bar: { type: 'string' },
- },
- },
- formData: { bar: 'bar' },
- });
-
- Simulate.change(node.querySelector('#root_bar'), {
- target: { value: 'baz' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: { bar: 'baz' },
- })
- );
- });
-
- it('should replace state when props change formData keys', () => {
- const formData = { foo: 'foo', bar: 'bar' };
- const { comp, node, onChange } = createFormComponent({
- schema,
- formData,
- });
-
- setProps(comp, {
- onChange,
- schema: {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- baz: { type: 'string' },
- },
+describe('Changing idPrefix', function () {
+ it('should work with simple example', function () {
+ const schema = {
+ type: 'object',
+ title: 'root object',
+ required: ['foo'],
+ properties: {
+ count: {
+ type: 'number',
},
- formData: { foo: 'foo', baz: 'bar' },
- });
-
- Simulate.change(node.querySelector('#root_baz'), {
- target: { value: 'baz' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- formData: { foo: 'foo', baz: 'baz' },
- })
- );
- });
+ },
+ };
+ const comp = renderIntoDocument();
+ const node = findDOMNode(comp);
+ const inputs = node.querySelectorAll('input');
+ const ids = [];
+ for (let i = 0, len = inputs.length; i < len; i++) {
+ const input = inputs[i];
+ ids.push(input.getAttribute('id'));
+ }
+ expect(ids).toStrictEqual(['rjsf_count']);
+ expect(node.querySelector('fieldset').id).toBe('rjsf');
});
- describe('idSchema updates based on formData', () => {
+ it('should work with oneOf', function () {
const schema = {
+ $schema: 'http://json-schema.org/draft-06/schema#',
type: 'object',
properties: {
- a: { type: 'string', enum: ['int', 'bool'] },
- },
- dependencies: {
- a: {
+ connector: {
oneOf: [
{
+ type: 'object',
properties: {
- a: { enum: ['int'] },
+ connector: {
+ type: 'string',
+ enum: ['aws'],
+ },
+ key_aws: {
+ type: 'string',
+ },
},
},
{
+ type: 'object',
properties: {
- a: { enum: ['bool'] },
- b: { type: 'boolean' },
+ connector: {
+ type: 'string',
+ enum: ['gcp'],
+ },
+ key_gcp: {
+ type: 'string',
+ },
},
},
],
@@ -2043,472 +216,490 @@ describe.each(formExtraPropsList)('Form with props: `%s`', formExtraProps => {
},
};
- it('should not update idSchema for a falsey value', () => {
- const formData = { a: 'int' };
- const { comp, node, onSubmit } = createFormComponent({
- schema,
- formData,
- });
+ const comp = renderIntoDocument();
+ const node = findDOMNode(comp);
+ const inputs = node.querySelectorAll('input');
+ const ids = [];
+ for (let i = 0, len = inputs.length; i < len; i++) {
+ const input = inputs[i];
+ ids.push(input.getAttribute('id'));
+ }
+ expect(ids).toStrictEqual(['rjsf_key_aws']);
+ });
+});
- setProps(comp, {
- onSubmit,
- schema: {
+describe('Custom field template', () => {
+ const schema = {
+ type: 'object',
+ title: 'root object',
+ required: ['foo'],
+ properties: {
+ foo: {
+ type: 'string',
+ description: 'this is description',
+ minLength: 32,
+ },
+ },
+ };
+
+ const uiSchema = {
+ foo: {
+ 'ui:help': 'this is help',
+ },
+ };
+
+ const formData = { foo: 'invalid' };
+
+ function FieldTemplate(props) {
+ const { id, classNames, label, help, rawHelp, required, description, rawDescription, children } = props;
+ return (
+
+
+ {label}
+ {required ? '*' : null}
+
+ {description}
+ {children}
+ {help}
+ {`${rawHelp} rendered from the raw format`}
+ {`${rawDescription} rendered from the raw format`}
+
+ );
+ }
+
+ let node;
+
+ beforeEach(() => {
+ node = createFormComponent({
+ schema,
+ uiSchema,
+ formData,
+ FieldTemplate,
+ }).node;
+ });
+
+ it('should use the provided field template', () => {
+ expect(node.querySelector('.my-template')).not.toBeNull();
+ });
+
+ it('should use the provided template for labels', () => {
+ expect(node.querySelector('.my-template > label')).toHaveTextContent('root object');
+ expect(node.querySelector('.my-template .field-string > label')).toHaveTextContent('foo*');
+ });
+
+ it('should pass description as the provided React element', () => {
+ expect(node.querySelector('#root_foo__description')).toHaveTextContent('this is description');
+ });
+
+ it('should pass rawDescription as a string', () => {
+ expect(node.querySelector('.raw-description')).toHaveTextContent(
+ 'this is description rendered from the raw format'
+ );
+ });
+
+ it('should pass help as a the provided React element', () => {
+ expect(node.querySelector('.help-block')).toHaveTextContent('this is help');
+ });
+
+ it('should pass rawHelp as a string', () => {
+ expect(node.querySelector('.raw-help')).toHaveTextContent('this is help rendered from the raw format');
+ });
+});
+
+describe('Schema definitions', () => {
+ it('should use a single schema definition reference', () => {
+ const schema = {
+ definitions: {
+ testdef: { type: 'string' },
+ },
+ $ref: '#/definitions/testdef',
+ };
+
+ const { node } = createFormComponent({ schema });
+
+ expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
+ });
+
+ it('should recursively handle refer multiple schema definition references', () => {
+ const schema = {
+ definitions: {
+ testdef: { type: 'string' },
+ },
+ type: 'object',
+ properties: {
+ foo: { $ref: '#/definitions/testdef' },
+ bar: { $ref: '#/definitions/testdef' },
+ },
+ };
+
+ const { node } = createFormComponent({ schema });
+
+ expect(node.querySelectorAll('input[type=text]')).toHaveLength(2);
+ });
+
+ it('should handle deeply referenced schema definitions', () => {
+ const schema = {
+ definitions: {
+ testdef: { type: 'string' },
+ },
+ type: 'object',
+ properties: {
+ foo: {
type: 'object',
properties: {
- a: { type: 'string', enum: ['int', 'bool'] },
- },
- dependencies: {
- a: {
- oneOf: [
- {
- properties: {
- a: { enum: ['int'] },
- },
- },
- {
- properties: {
- a: { enum: ['bool'] },
- b: { type: 'boolean' },
- },
- },
- ],
- },
+ bar: { $ref: '#/definitions/testdef' },
},
},
- formData: { a: 'int' },
- });
+ },
+ };
- submitForm(node);
- expect(onSubmit).toHaveBeenLastCalledWith(
- expect.objectContaining({
- idSchema: { $id: 'root', a: { $id: 'root_a' } },
- }),
- expect.anything()
- );
- });
+ const { node } = createFormComponent({ schema });
- it('should update idSchema based on truthy value', () => {
- const formData = {
- a: 'int',
- };
- const { comp, node, onSubmit } = createFormComponent({
- schema,
- formData,
- });
- setProps(comp, {
- onSubmit,
- schema: {
+ expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
+ });
+
+ it('should handle references to deep schema definitions', () => {
+ const schema = {
+ definitions: {
+ testdef: {
type: 'object',
properties: {
- a: { type: 'string', enum: ['int', 'bool'] },
- },
- dependencies: {
- a: {
- oneOf: [
- {
- properties: {
- a: { enum: ['int'] },
- },
- },
- {
- properties: {
- a: { enum: ['bool'] },
- b: { type: 'boolean' },
- },
- },
- ],
- },
+ bar: { type: 'string' },
},
},
- formData: { a: 'bool' },
- });
- submitForm(node);
- expect(onSubmit).toHaveBeenLastCalledWith(
- expect.objectContaining({
- idSchema: {
- $id: 'root',
- a: { $id: 'root_a' },
- b: { $id: 'root_b' },
- },
- }),
- expect.anything()
- );
+ },
+ type: 'object',
+ properties: {
+ foo: { $ref: '#/definitions/testdef/properties/bar' },
+ },
+ };
+
+ const { node } = createFormComponent({ schema });
+
+ expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
+ });
+
+ it('should handle referenced definitions for array items', () => {
+ const schema = {
+ definitions: {
+ testdef: { type: 'string' },
+ },
+ type: 'object',
+ properties: {
+ foo: {
+ type: 'array',
+ items: { $ref: '#/definitions/testdef' },
+ },
+ },
+ };
+
+ const { node } = createFormComponent({
+ schema,
+ formData: {
+ foo: ['blah'],
+ },
});
+
+ expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
});
- describe('Form disable prop', () => {
+ it('should raise for non-existent definitions referenced', () => {
const schema = {
type: 'object',
properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
+ foo: { $ref: '#/definitions/nonexistent' },
},
};
- const formData = { foo: 'foo', bar: 'bar' };
- it('should enable all items', () => {
- const { node } = createFormComponent({ schema, formData });
+ expect(() => createFormComponent({ schema })).toThrow(/#\/definitions\/nonexistent/);
+ });
- expect(node.querySelectorAll('input:disabled')).toHaveLength(0);
- });
+ it('should propagate referenced definition defaults', () => {
+ const schema = {
+ definitions: {
+ testdef: { type: 'string', default: 'hello' },
+ },
+ $ref: '#/definitions/testdef',
+ };
- it('should disable all items', () => {
- const { node } = createFormComponent({
- schema,
- formData,
- disabled: true,
- });
+ const { node } = createFormComponent({ schema });
- expect(node.querySelectorAll('input:disabled')).toHaveLength(2);
- });
+ expect(node.querySelector('input[type=text]').value).toBe('hello');
});
- describe('Attributes', () => {
- const formProps = {
- schema: {},
- id: 'test-form',
- className: 'test-class other-class',
- name: 'testName',
- method: 'post',
- target: '_blank',
- action: '/users/list',
- autoComplete: 'off',
- enctype: 'multipart/form-data',
- acceptcharset: 'ISO-8859-1',
- noHtml5Validate: true,
+ it('should propagate nested referenced definition defaults', () => {
+ const schema = {
+ definitions: {
+ testdef: { type: 'string', default: 'hello' },
+ },
+ type: 'object',
+ properties: {
+ foo: { $ref: '#/definitions/testdef' },
+ },
};
- let node;
+ const { node } = createFormComponent({ schema });
- beforeEach(() => {
- node = createFormComponent(formProps).node;
- });
+ expect(node.querySelector('input[type=text]').value).toBe('hello');
+ });
- it('should set attr id of form', () => {
- expect(node).toHaveAttribute('id', formProps.id);
- });
+ it('should propagate referenced definition defaults for array items', () => {
+ const schema = {
+ definitions: {
+ testdef: { type: 'string', default: 'hello' },
+ },
+ type: 'array',
+ items: {
+ $ref: '#/definitions/testdef',
+ },
+ };
- it('should set attr class of form', () => {
- expect(node).toHaveAttribute('class', formProps.className);
- });
+ const { node } = createFormComponent({ schema });
- it('should set attr name of form', () => {
- expect(node).toHaveAttribute('name', formProps.name);
- });
+ Simulate.click(node.querySelector('.array-item-add button'));
+
+ expect(node.querySelector('input[type=text]').value).toBe('hello');
+ });
+
+ it('should propagate referenced definition defaults in objects with additionalProperties', () => {
+ const schema = {
+ definitions: {
+ testdef: { type: 'string' },
+ },
+ type: 'object',
+ additionalProperties: {
+ $ref: '#/definitions/testdef',
+ },
+ };
- it('should set attr method of form', () => {
- expect(node).toHaveAttribute('method', formProps.method);
- });
+ const { node } = createFormComponent({ schema });
- it('should set attr target of form', () => {
- expect(node).toHaveAttribute('target', formProps.target);
- });
+ Simulate.click(node.querySelector('.btn-add'));
- it('should set attr action of form', () => {
- expect(node).toHaveAttribute('action', formProps.action);
- });
+ expect(node.querySelector('input[type=text]').value).toBe('newKey');
+ });
- it('should set attr autocomplete of form', () => {
- expect(node).toHaveAttribute('autocomplete', formProps.autoComplete);
- });
+ it('should propagate referenced definition defaults in objects with additionalProperties that have a type present', () => {
+ // Though `additionalProperties` has a `type` present here, it also has a `$ref` so that
+ // referenced schema should override it.
+ const schema = {
+ definitions: {
+ testdef: { type: 'number' },
+ },
+ type: 'object',
+ additionalProperties: {
+ type: 'string',
+ $ref: '#/definitions/testdef',
+ },
+ };
- it('should set attr enctype of form', () => {
- expect(node).toHaveAttribute('enctype', formProps.enctype);
- });
+ const { node } = createFormComponent({ schema });
- it('should set attr acceptcharset of form', () => {
- expect(node).toHaveAttribute('accept-charset', formProps.acceptcharset);
- });
+ Simulate.click(node.querySelector('.btn-add'));
- it('should set attr novalidate of form', () => {
- expect(node.getAttribute('novalidate')).not.toBeNull();
- });
+ expect(node.querySelector('input[type=number]').value).toBe('0');
});
- describe('Deprecated autocomplete attribute', () => {
- it('should set attr autocomplete of form', () => {
- const formProps = {
- schema: {},
- autocomplete: 'off',
- };
- const node = createFormComponent(formProps).node;
- expect(node).toHaveAttribute('autocomplete', formProps.autocomplete);
- });
+ it('should follow recursive references', () => {
+ const schema = {
+ definitions: {
+ bar: { $ref: '#/definitions/qux' },
+ qux: { type: 'string' },
+ },
+ type: 'object',
+ required: ['foo'],
+ properties: {
+ foo: { $ref: '#/definitions/bar' },
+ },
+ };
+ const { node } = createFormComponent({ schema });
- it('should log deprecation warning when it is used', () => {
- jest.spyOn(console, 'warn').mockImplementation(() => {});
- createFormComponent({
- schema: {},
- autocomplete: 'off',
- });
- expect(console.warn).toHaveBeenCalledWith(
- expect.stringMatching(/Using autocomplete property of Form is deprecated/)
- );
- });
+ expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
+ });
- it('should use autoComplete value if both autocomplete and autoComplete are used', () => {
- const formProps = {
- schema: {},
- autocomplete: 'off',
- autoComplete: 'on',
- };
- const node = createFormComponent(formProps).node;
- expect(node).toHaveAttribute('autocomplete', formProps.autoComplete);
- });
+ it('should follow multiple recursive references', () => {
+ const schema = {
+ definitions: {
+ bar: { $ref: '#/definitions/bar2' },
+ bar2: { $ref: '#/definitions/qux' },
+ qux: { type: 'string' },
+ },
+ type: 'object',
+ required: ['foo'],
+ properties: {
+ foo: { $ref: '#/definitions/bar' },
+ },
+ };
+ const { node } = createFormComponent({ schema });
+
+ expect(node.querySelectorAll('input[type=text]')).toHaveLength(1);
});
- describe('Custom format updates', () => {
- it('should update custom formats when customFormats is changed', () => {
- const formProps = {
- liveValidate: true,
- formData: {
- areaCode: '123455',
+ it('should priorize definition over schema type property', () => {
+ // Refs bug #140
+ const schema = {
+ type: 'object',
+ properties: {
+ name: { type: 'string' },
+ childObj: {
+ type: 'object',
+ $ref: '#/definitions/childObj',
},
- schema: {
+ },
+ definitions: {
+ childObj: {
type: 'object',
properties: {
- areaCode: {
- type: 'string',
- format: 'area-code',
- },
- },
- },
- uiSchema: {
- areaCode: {
- 'ui:widget': 'area-code',
+ otherName: { type: 'string' },
},
},
- widgets: {
- 'area-code': () =>
,
- },
- };
-
- const { comp, node, onError } = createFormComponent(formProps);
-
- submitForm(node);
- expect(onError).not.toHaveBeenCalled();
+ },
+ };
- setProps(comp, {
- ...formProps,
- onError,
- customFormats: {
- 'area-code': /^\d{3}$/,
- },
- });
+ const { node } = createFormComponent({ schema });
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should match format "area-code"',
- name: 'format',
- params: { format: 'area-code' },
- property: '.areaCode',
- schemaPath: '#/properties/areaCode/format',
- stack: '.areaCode should match format "area-code"',
- },
- ])
- );
- });
+ expect(node.querySelectorAll('input[type=text]')).toHaveLength(2);
});
- describe('Meta schema updates', () => {
- it('Should update allowed meta schemas when additionalMetaSchemas is changed', () => {
- const formProps = {
- liveValidate: true,
- schema: {
- $schema: 'http://json-schema.org/draft-04/schema#',
- type: 'string',
- minLength: 8,
- pattern: 'd+',
+ it('should priorize local properties over definition ones', () => {
+ // Refs bug #140
+ const schema = {
+ type: 'object',
+ properties: {
+ foo: {
+ title: 'custom title',
+ $ref: '#/definitions/objectDef',
},
- formData: 'short',
- additionalMetaSchemas: [],
- };
-
- const { comp, node, onError } = createFormComponent(formProps);
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- stack: 'no schema with key or ref "http://json-schema.org/draft-04/schema#"',
- },
- ])
- );
-
- setProps(comp, {
- ...formProps,
- onError,
- additionalMetaSchemas: [require('ajv/lib/refs/json-schema-draft-04.json')],
- });
-
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should NOT be shorter than 8 characters',
- name: 'minLength',
- params: { limit: 8 },
- property: '',
- schemaPath: '#/minLength',
- stack: 'should NOT be shorter than 8 characters',
- },
- {
- message: 'should match pattern "d+"',
- name: 'pattern',
- params: { pattern: 'd+' },
- property: '',
- schemaPath: '#/pattern',
- stack: 'should match pattern "d+"',
+ },
+ definitions: {
+ objectDef: {
+ type: 'object',
+ title: 'definition title',
+ properties: {
+ field: { type: 'string' },
},
- ])
- );
+ },
+ },
+ };
- setProps(comp, { ...formProps, onError });
+ const { node } = createFormComponent({ schema });
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- stack: 'no schema with key or ref "http://json-schema.org/draft-04/schema#"',
- },
- ])
- );
- });
+ expect(node.querySelector('legend')).toHaveTextContent('custom title');
});
- describe('Changing the tagName', () => {
- it('should render the component using the custom tag name', () => {
- const tagName = 'span';
- const { node } = createFormComponent({ schema: {}, tagName });
- expect(node.tagName).toBe(tagName.toUpperCase());
- });
+ it('should propagate and handle a resolved schema definition', () => {
+ const schema = {
+ definitions: {
+ enumDef: { type: 'string', enum: ['a', 'b'] },
+ },
+ type: 'object',
+ properties: {
+ name: { $ref: '#/definitions/enumDef' },
+ },
+ };
- it('should render the component using a ComponentType', () => {
- const Component = props =>
;
- const { node } = createFormComponent({ schema: {}, tagName: Component });
- expect(node.id).toBe('test');
- });
+ const { node } = createFormComponent({ schema });
+
+ expect(node.querySelectorAll('option')).toHaveLength(3);
});
+});
- describe('Nested forms', () => {
- it('should call provided submit handler with form state', () => {
- const innerOnSubmit = jest.fn();
- const outerOnSubmit = jest.fn();
- let innerRef;
-
- class ArrayTemplateWithForm extends React.Component {
- constructor(props) {
- super(props);
- innerRef = createRef();
- }
-
- render() {
- const innerFormProps = {
- schema: {},
- onSubmit: innerOnSubmit,
- };
-
- return (
-
-
-
-
-
- );
- }
- }
+describe('Default value handling on clear', () => {
+ const schema = {
+ type: 'string',
+ default: 'foo',
+ };
- const outerFormProps = {
- schema: {
- type: 'array',
- title: 'my list',
- description: 'my description',
- items: { type: 'string' },
- },
- formData: ['foo', 'bar'],
- ArrayFieldTemplate: ArrayTemplateWithForm,
- onSubmit: outerOnSubmit,
- };
- createFormComponent(outerFormProps);
- const arrayForm = innerRef.current.querySelector('form');
- const arraySubmit = arrayForm.querySelector('.array-form-submit');
+ it('should not set default when a text field is cleared', () => {
+ const { node } = createFormComponent({ schema, formData: 'bar' });
- arraySubmit.click();
- expect(innerOnSubmit).toHaveBeenCalledTimes(1);
- expect(outerOnSubmit).not.toHaveBeenCalled();
+ Simulate.change(node.querySelector('input'), {
+ target: { value: '' },
});
+
+ expect(node.querySelector('input').value).toBe('');
});
+});
- describe('Dependencies', () => {
- it('should not give a validation error by duplicating enum values in dependencies', () => {
- const schema = {
- title: 'A registration form',
- description: 'A simple form example.',
+describe('Defaults array items default propagation', () => {
+ const schema = {
+ type: 'object',
+ title: 'lvl 1 obj',
+ properties: {
+ object: {
type: 'object',
+ title: 'lvl 2 obj',
properties: {
- type1: {
- type: 'string',
- title: 'Type 1',
- enum: ['FOO', 'BAR', 'BAZ'],
- },
- type2: {
- type: 'string',
- title: 'Type 2',
- enum: ['GREEN', 'BLUE', 'RED'],
- },
- },
- dependencies: {
- type1: {
- properties: {
- type1: {
- enum: ['FOO'],
- },
- type2: {
- enum: ['GREEN'],
+ array: {
+ type: 'array',
+ items: {
+ type: 'object',
+ title: 'lvl 3 obj',
+ properties: {
+ bool: {
+ type: 'boolean',
+ default: true,
+ },
},
},
},
},
- };
- const formData = {
- type1: 'FOO',
- };
- const { node, onError } = createFormComponent({ schema, formData });
- Simulate.submit(node);
- expect(onError).not.toHaveBeenCalled();
- });
+ },
+ },
+ };
- it('should show dependency defaults for uncontrolled components', () => {
- const schema = {
- type: 'object',
- properties: {
- firstName: { type: 'string' },
- },
- dependencies: {
- firstName: {
- properties: {
- lastName: { type: 'string', default: 'Norris' },
- },
+ it('should propagate deeply nested defaults to submit handler', () => {
+ const { node, onSubmit } = createFormComponent({ schema });
+
+ Simulate.click(node.querySelector('.array-item-add button'));
+ Simulate.submit(node);
+
+ expect(onSubmit).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ formData: {
+ object: {
+ array: [
+ {
+ bool: true,
+ },
+ ],
},
},
- };
- const { node } = createFormComponent({ schema });
+ }),
+ expect.anything()
+ );
+ });
+});
- Simulate.change(node.querySelector('#root_firstName'), {
- target: { value: 'Chuck' },
- });
- expect(node.querySelector('#root_lastName').value).toBe('Norris');
+describe('Submit handler', () => {
+ it('should call provided submit handler with form state', () => {
+ const schema = {
+ type: 'object',
+ properties: {
+ foo: { type: 'string' },
+ },
+ };
+ const formData = {
+ foo: 'bar',
+ };
+ const onSubmit = jest.fn();
+ const event = { type: 'submit' };
+ const { node } = createFormComponent({
+ schema,
+ formData,
+ onSubmit,
});
+
+ Simulate.submit(node, event);
+ expect(onSubmit).toHaveBeenLastCalledWith(
+ expect.objectContaining({ formData, schema }),
+ expect.objectContaining(event)
+ );
});
});
-describe('Form omitExtraData and liveOmit', () => {
- it('should call getUsedFormData when the omitExtraData prop is true and liveOmit is true', () => {
+describe('Change handler', () => {
+ it('should call provided change handler on form state change', () => {
const schema = {
type: 'object',
properties: {
@@ -2518,31 +709,31 @@ describe('Form omitExtraData and liveOmit', () => {
},
};
const formData = {
- foo: 'bar',
+ foo: '',
};
const onChange = jest.fn();
- const omitExtraData = true;
- const liveOmit = true;
- const { node, comp } = createFormComponent({
+ const { node } = createFormComponent({
schema,
formData,
onChange,
- omitExtraData,
- liveOmit,
});
- jest.spyOn(comp, 'getUsedFormData').mockImplementation(() => ({
- foo: '',
- }));
-
Simulate.change(node.querySelector('[type=text]'), {
target: { value: 'new' },
});
- expect(comp.getUsedFormData).toHaveBeenCalledTimes(1);
+ expect(onChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ formData: {
+ foo: 'new',
+ },
+ })
+ );
});
+});
- it('should not call getUsedFormData when the omitExtraData prop is true and liveOmit is unspecified', () => {
+describe('Blur handler', () => {
+ it('should call provided blur handler on form input blur event', () => {
const schema = {
type: 'object',
properties: {
@@ -2552,473 +743,561 @@ describe('Form omitExtraData and liveOmit', () => {
},
};
const formData = {
- foo: 'bar',
- };
- const onChange = jest.fn();
- const omitExtraData = true;
- const { node, comp } = createFormComponent({
- schema,
- formData,
- onChange,
- omitExtraData,
- });
-
- jest.spyOn(comp, 'getUsedFormData').mockImplementation(() => ({
foo: '',
- }));
+ };
+ const onBlur = jest.fn();
+ const { node } = createFormComponent({ schema, formData, onBlur });
- Simulate.change(node.querySelector('[type=text]'), {
+ const input = node.querySelector('[type=text]');
+ Simulate.blur(input, {
target: { value: 'new' },
});
- expect(comp.getUsedFormData).not.toHaveBeenCalled();
+ expect(onBlur).toHaveBeenCalledWith(input.id, 'new');
});
+});
- describe('getUsedFormData', () => {
- it('should call getUsedFormData when the omitExtraData prop is true', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: {
- type: 'string',
- },
+describe('Focus handler', () => {
+ it('should call provided focus handler on form input focus event', () => {
+ const schema = {
+ type: 'object',
+ properties: {
+ foo: {
+ type: 'string',
},
- };
- const formData = {
- foo: '',
- };
- const onSubmit = jest.fn();
- const onError = jest.fn();
- const omitExtraData = true;
- const { comp, node } = createFormComponent({
- schema,
- formData,
- onSubmit,
- onError,
- omitExtraData,
- });
-
- jest.spyOn(comp, 'getUsedFormData').mockImplementation(() => ({
- foo: '',
- }));
-
- Simulate.submit(node);
+ },
+ };
+ const formData = {
+ foo: '',
+ };
+ const onFocus = jest.fn();
+ const { node } = createFormComponent({ schema, formData, onFocus });
- expect(comp.getUsedFormData).toHaveBeenCalledTimes(1);
+ const input = node.querySelector('[type=text]');
+ Simulate.focus(input, {
+ target: { value: 'new' },
});
- it('should just return the single input form value', () => {
- const schema = {
- title: 'A single-field form',
- type: 'string',
- };
- const formData = 'foo';
- const onSubmit = jest.fn();
- const { comp } = createFormComponent({
- schema,
- formData,
- onSubmit,
- });
+ expect(onFocus).toHaveBeenCalledWith(input.id, 'new');
+ });
+});
- const result = comp.getUsedFormData(formData, []);
- expect(result).toBe('foo');
- });
+describe('Schema and external formData updates', () => {
+ let comp;
+ let onChangeProp;
+ let formProps;
- it('should return the root level array', () => {
- const schema = {
- type: 'array',
- items: {
- type: 'string',
- },
- };
- const formData = [];
- const onSubmit = jest.fn();
- const { comp } = createFormComponent({
- schema,
- formData,
- onSubmit,
- });
+ beforeEach(() => {
+ onChangeProp = jest.fn();
+ formProps = {
+ schema: {
+ type: 'string',
+ default: 'foobar',
+ },
+ formData: 'some value',
+ onChange: onChangeProp,
+ };
+ comp = createFormComponent(formProps).comp;
+ });
- const result = comp.getUsedFormData(formData, []);
- expect(result).toStrictEqual([]);
- });
+ describe('when the form data is set to null', () => {
+ beforeEach(() =>
+ setProps(comp, {
+ ...formProps,
+ formData: null,
+ })
+ );
- it('should call getUsedFormData with data from fields in event', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- },
- };
- const formData = {
- foo: 'bar',
- };
- const onSubmit = jest.fn();
- const { comp } = createFormComponent({
- schema,
- formData,
- onSubmit,
+ it('should call onChange', () => {
+ expect(onChangeProp).toHaveBeenCalledTimes(1);
+ expect(onChangeProp).toHaveBeenCalledWith({
+ edit: true,
+ formData: 'foobar',
+ idSchema: { $id: 'root' },
+ schema: formProps.schema,
+ uiSchema: {},
});
-
- const result = comp.getUsedFormData(formData, ['foo']);
- expect(result).toStrictEqual({ foo: 'bar' });
});
+ });
- it('unused form values should be omitted', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- baz: { type: 'string' },
- list: {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- title: { type: 'string' },
- details: { type: 'string' },
- },
- },
- },
- },
- };
+ describe('when the schema default is changed but formData is not changed', () => {
+ const newSchema = {
+ type: 'string',
+ default: 'the new default',
+ };
- const formData = {
- foo: 'bar',
- baz: 'buzz',
- list: [
- { title: 'title0', details: 'details0' },
- { title: 'title1', details: 'details1' },
- ],
- };
- const onSubmit = jest.fn();
- const { comp } = createFormComponent({
- schema,
- formData,
- onSubmit,
- });
+ beforeEach(() =>
+ setProps(comp, {
+ ...formProps,
+ schema: newSchema,
+ formData: 'some value',
+ })
+ );
- const result = comp.getUsedFormData(formData, ['foo', 'list.0.title', 'list.1.details']);
- expect(result).toStrictEqual({
- foo: 'bar',
- list: [{ title: 'title0' }, { details: 'details1' }],
- });
+ it('should not call onChange', () => {
+ expect(onChangeProp).not.toHaveBeenCalled();
});
});
- describe('getFieldNames()', () => {
- it('should return an empty array for a single input form', () => {
- const schema = {
- type: 'string',
- };
+ describe('when the schema default is changed and formData is changed', () => {
+ const newSchema = {
+ type: 'string',
+ default: 'the new default',
+ };
+
+ beforeEach(() =>
+ setProps(comp, {
+ ...formProps,
+ schema: newSchema,
+ formData: 'something else',
+ })
+ );
- const formData = 'foo';
+ it('should not call onChange', () => {
+ expect(onChangeProp).not.toHaveBeenCalled();
+ });
+ });
- const onSubmit = jest.fn();
- const { comp } = createFormComponent({
- schema,
- formData,
- onSubmit,
- });
+ describe('when the schema default is changed and formData is nulled', () => {
+ const newSchema = {
+ type: 'string',
+ default: 'the new default',
+ };
- const pathSchema = {
- $name: '',
- };
+ beforeEach(() =>
+ setProps(comp, {
+ ...formProps,
+ schema: newSchema,
+ formData: null,
+ })
+ );
- const fieldNames = comp.getFieldNames(pathSchema, formData);
- expect(fieldNames).toStrictEqual([]);
+ it('should call onChange', () => {
+ expect(onChangeProp).toHaveBeenCalledTimes(1);
+ expect(onChangeProp).toHaveBeenCalledWith(
+ expect.objectContaining({
+ schema: newSchema,
+ formData: 'the new default',
+ })
+ );
});
+ });
- it('should get field names from pathSchema', () => {
- const schema = {};
+ describe('when the onChange prop sets formData to a falsey value', () => {
+ class TestForm extends React.Component {
+ constructor() {
+ super();
- const formData = {
- extra: {
- foo: 'bar',
- },
- level1: {
- level2: 'test',
- anotherThing: {
- anotherThingNested: 'abc',
- extra: 'asdf',
- anotherThingNested2: 0,
- },
- },
- level1a: 1.23,
- };
+ this.state = {
+ formData: {},
+ };
+ }
- const onSubmit = jest.fn();
- const { comp } = createFormComponent({
- schema,
- formData,
- onSubmit,
- });
+ onChange = () => {
+ this.setState({ formData: this.props.falseyValue });
+ };
- const pathSchema = {
- $name: '',
- level1: {
- $name: 'level1',
- level2: { $name: 'level1.level2' },
- anotherThing: {
- $name: 'level1.anotherThing',
- anotherThingNested: {
- $name: 'level1.anotherThing.anotherThingNested',
- },
- anotherThingNested2: {
- $name: 'level1.anotherThing.anotherThingNested2',
+ render() {
+ const schema = {
+ type: 'object',
+ properties: {
+ value: {
+ type: 'string',
},
},
- },
- level1a: {
- $name: 'level1a',
- },
- };
+ };
+ return ;
+ }
+ }
+
+ it.each([[0], [false], [null], [undefined], [NaN]])(
+ 'should not crash due to "Maximum call stack size exceeded..." with `%s`"',
+ falsyValue => {
+ // It is expected that this will throw an error due to non-matching propTypes,
+ // so the error message needs to be inspected
+ expect(() => {
+ createComponent(TestForm, { falsyValue });
+ }).not.toThrow('Maximum call stack size exceeded');
+ }
+ );
+ });
+});
+
+describe('External formData updates', () => {
+ describe('root level', () => {
+ const formProps = {
+ schema: { type: 'string' },
+ };
- const fieldNames = comp.getFieldNames(pathSchema, formData);
- expect(fieldNames.sort()).toStrictEqual(
- [
- 'level1a',
- 'level1.level2',
- 'level1.anotherThing.anotherThingNested',
- 'level1.anotherThing.anotherThingNested2',
- ].sort()
+ it('should call submit handler with new formData prop value', () => {
+ const { comp, node, onSubmit } = createFormComponent(formProps);
+
+ setProps(comp, {
+ ...formProps,
+ onSubmit,
+ formData: 'yo',
+ });
+ submitForm(node);
+ expect(onSubmit).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ formData: 'yo',
+ }),
+ expect.anything()
);
});
+ });
- it('should get field names from pathSchema with array', () => {
- const schema = {};
-
- const formData = {
- address_list: [
- {
- street_address: '21, Jump Street',
- city: 'Babel',
- state: 'Neverland',
- },
- {
- street_address: '1234 Schema Rd.',
- city: 'New York',
- state: 'Arizona',
- },
- ],
+ describe('object level', () => {
+ it('should call submit handler with new formData prop value', () => {
+ const formProps = {
+ schema: { type: 'object', properties: { foo: { type: 'string' } } },
};
+ const { comp, onSubmit, node } = createFormComponent(formProps);
- const onSubmit = jest.fn();
- const { comp } = createFormComponent({
- schema,
- formData,
+ setProps(comp, {
+ ...formProps,
onSubmit,
+ formData: { foo: 'yo' },
});
- const pathSchema = {
- $name: '',
- address_list: {
- 0: {
- $name: 'address_list.0',
- city: {
- $name: 'address_list.0.city',
- },
- state: {
- $name: 'address_list.0.state',
- },
- street_address: {
- $name: 'address_list.0.street_address',
- },
- },
- 1: {
- $name: 'address_list.1',
- city: {
- $name: 'address_list.1.city',
- },
- state: {
- $name: 'address_list.1.state',
- },
- street_address: {
- $name: 'address_list.1.street_address',
- },
- },
+ submitForm(node);
+ expect(onSubmit).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ formData: { foo: 'yo' },
+ }),
+ expect.anything()
+ );
+ });
+ });
+
+ describe('array level', () => {
+ it('should call submit handler with new formData prop value', () => {
+ const schema = {
+ type: 'array',
+ items: {
+ type: 'string',
},
};
+ const { comp, node, onSubmit } = createFormComponent({ schema });
+
+ setProps(comp, { schema, onSubmit, formData: ['yo'] });
- const fieldNames = comp.getFieldNames(pathSchema, formData);
- expect(fieldNames.sort()).toStrictEqual(
- [
- 'address_list.0.city',
- 'address_list.0.state',
- 'address_list.0.street_address',
- 'address_list.1.city',
- 'address_list.1.state',
- 'address_list.1.street_address',
- ].sort()
+ submitForm(node);
+ expect(onSubmit).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ formData: ['yo'],
+ }),
+ expect.anything()
);
});
});
+});
- it('should not omit data on change with omitExtraData=false and liveOmit=false', () => {
- const omitExtraData = false;
- const liveOmit = false;
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
- },
+describe('Internal formData updates', () => {
+ it('root', () => {
+ const formProps = {
+ schema: { type: 'string' },
};
- const formData = { foo: 'foo', baz: 'baz' };
- const { node, onChange } = createFormComponent({
- schema,
- formData,
- omitExtraData,
- liveOmit,
- });
+ const { node, onChange } = createFormComponent(formProps);
- Simulate.change(node.querySelector('#root_foo'), {
- target: { value: 'foobar' },
+ Simulate.change(node.querySelector('input[type=text]'), {
+ target: { value: 'yo' },
});
expect(onChange).toHaveBeenLastCalledWith(
expect.objectContaining({
- formData: { foo: 'foobar', baz: 'baz' },
+ formData: 'yo',
})
);
});
- it('should not omit data on change with omitExtraData=true and liveOmit=false', () => {
- const omitExtraData = true;
- const liveOmit = false;
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
- },
- };
- const formData = { foo: 'foo', baz: 'baz' };
+ it('object', () => {
const { node, onChange } = createFormComponent({
- schema,
- formData,
- omitExtraData,
- liveOmit,
+ schema: {
+ type: 'object',
+ properties: {
+ foo: {
+ type: 'string',
+ },
+ },
+ },
});
- Simulate.change(node.querySelector('#root_foo'), {
- target: { value: 'foobar' },
+ Simulate.change(node.querySelector('input[type=text]'), {
+ target: { value: 'yo' },
});
expect(onChange).toHaveBeenLastCalledWith(
expect.objectContaining({
- formData: { foo: 'foobar', baz: 'baz' },
+ formData: { foo: 'yo' },
})
);
});
- it('should not omit data on change with omitExtraData=false and liveOmit=true', () => {
- const omitExtraData = false;
- const liveOmit = true;
+ it('array of strings', () => {
const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
+ type: 'array',
+ items: {
+ type: 'string',
},
};
- const formData = { foo: 'foo', baz: 'baz' };
- const { node, onChange } = createFormComponent({
- schema,
- formData,
- omitExtraData,
- liveOmit,
- });
+ const { node, onChange } = createFormComponent({ schema });
- Simulate.change(node.querySelector('#root_foo'), {
- target: { value: 'foobar' },
- });
+ Simulate.click(node.querySelector('.array-item-add button'));
+ Simulate.change(node.querySelector('input[type=text]'), {
+ target: { value: 'yo' },
+ });
expect(onChange).toHaveBeenLastCalledWith(
expect.objectContaining({
- formData: { foo: 'foobar', baz: 'baz' },
+ formData: ['yo'],
})
);
});
- it('should omit data on change with omitExtraData=true and liveOmit=true', () => {
- const omitExtraData = true;
- const liveOmit = true;
+ it('array of objects', () => {
const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ name: { type: 'string' },
+ },
},
};
- const formData = { foo: 'foo', baz: 'baz' };
- const { node, onChange } = createFormComponent({
- schema,
- formData,
- omitExtraData,
- liveOmit,
- });
+ const { node, onChange } = createFormComponent({ schema });
+
+ Simulate.click(node.querySelector('.array-item-add button'));
- Simulate.change(node.querySelector('#root_foo'), {
- target: { value: 'foobar' },
+ Simulate.change(node.querySelector('input[type=text]'), {
+ target: { value: 'yo' },
});
expect(onChange).toHaveBeenLastCalledWith(
expect.objectContaining({
- formData: { foo: 'foobar' },
+ formData: [{ name: 'yo' }],
})
);
});
+});
- describe('Async errors', () => {
- it('should render the async errors', () => {
- const schema = {
+describe('Schema and formData updates', () => {
+ // https://github.com/mozilla-services/react-jsonschema-form/issues/231
+ const schema = {
+ type: 'object',
+ properties: {
+ foo: { type: 'string' },
+ bar: { type: 'string' },
+ },
+ };
+
+ it('should replace state when props remove formData keys', () => {
+ const formData = { foo: 'foo', bar: 'bar' };
+ const { comp, node, onChange } = createFormComponent({
+ schema,
+ formData,
+ });
+
+ setProps(comp, {
+ onChange,
+ schema: {
type: 'object',
properties: {
- foo: { type: 'string' },
- candy: {
- type: 'object',
- properties: {
- bar: { type: 'string' },
- },
- },
+ bar: { type: 'string' },
},
- };
+ },
+ formData: { bar: 'bar' },
+ });
- const extraErrors = {
- foo: {
- __errors: ['some error that got added as a prop'],
- },
- candy: {
- bar: {
- __errors: ['some other error that got added as a prop'],
- },
- },
- };
+ Simulate.change(node.querySelector('#root_bar'), {
+ target: { value: 'baz' },
+ });
- const { node } = createFormComponent({ schema, extraErrors });
+ expect(onChange).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ formData: { bar: 'baz' },
+ })
+ );
+ });
- expect(node.querySelectorAll('.error-detail li')).toHaveLength(2);
+ it('should replace state when props change formData keys', () => {
+ const formData = { foo: 'foo', bar: 'bar' };
+ const { comp, node, onChange } = createFormComponent({
+ schema,
+ formData,
});
- it('should not block form submission', () => {
- const onSubmit = jest.fn();
- const schema = {
+ setProps(comp, {
+ onChange,
+ schema: {
type: 'object',
properties: {
foo: { type: 'string' },
+ baz: { type: 'string' },
},
- };
+ },
+ formData: { foo: 'foo', baz: 'bar' },
+ });
- const extraErrors = {
- foo: {
- __errors: ['some error that got added as a prop'],
- },
- };
+ Simulate.change(node.querySelector('#root_baz'), {
+ target: { value: 'baz' },
+ });
+
+ expect(onChange).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ formData: { foo: 'foo', baz: 'baz' },
+ })
+ );
+ });
+});
+
+describe('Form disable prop', () => {
+ const schema = {
+ type: 'object',
+ properties: {
+ foo: { type: 'string' },
+ bar: { type: 'string' },
+ },
+ };
+ const formData = { foo: 'foo', bar: 'bar' };
- const { node } = createFormComponent({ schema, extraErrors, onSubmit });
- Simulate.submit(node);
- expect(onSubmit).toHaveBeenCalledTimes(1);
+ it('should enable all items', () => {
+ const { node } = createFormComponent({ schema, formData });
+
+ expect(node.querySelectorAll('input:disabled')).toHaveLength(0);
+ });
+
+ it('should disable all items', () => {
+ const { node } = createFormComponent({
+ schema,
+ formData,
+ disabled: true,
});
+
+ expect(node.querySelectorAll('input:disabled')).toHaveLength(2);
+ });
+});
+
+describe('Attributes', () => {
+ const formProps = {
+ schema: {},
+ id: 'test-form',
+ className: 'test-class other-class',
+ name: 'testName',
+ method: 'post',
+ target: '_blank',
+ action: '/users/list',
+ autoComplete: 'off',
+ enctype: 'multipart/form-data',
+ acceptcharset: 'ISO-8859-1',
+ };
+
+ let node;
+
+ beforeEach(() => {
+ node = createFormComponent(formProps).node;
+ });
+
+ it('should set attr id of form', () => {
+ expect(node).toHaveAttribute('id', formProps.id);
+ });
+
+ it('should set attr class of form', () => {
+ expect(node).toHaveAttribute('class', formProps.className);
+ });
+
+ it('should set attr name of form', () => {
+ expect(node).toHaveAttribute('name', formProps.name);
+ });
+
+ it('should set attr method of form', () => {
+ expect(node).toHaveAttribute('method', formProps.method);
+ });
+
+ it('should set attr target of form', () => {
+ expect(node).toHaveAttribute('target', formProps.target);
+ });
+
+ it('should set attr action of form', () => {
+ expect(node).toHaveAttribute('action', formProps.action);
+ });
+
+ it('should set attr autocomplete of form', () => {
+ expect(node).toHaveAttribute('autocomplete', formProps.autoComplete);
+ });
+
+ it('should set attr enctype of form', () => {
+ expect(node).toHaveAttribute('enctype', formProps.enctype);
+ });
+
+ it('should set attr acceptcharset of form', () => {
+ expect(node).toHaveAttribute('accept-charset', formProps.acceptcharset);
+ });
+});
+
+describe('Changing the tagName', () => {
+ it('should render the component using the custom tag name', () => {
+ const tagName = 'span';
+ const { node } = createFormComponent({ schema: {}, tagName });
+ expect(node.tagName).toBe(tagName.toUpperCase());
+ });
+
+ it('should render the component using a ComponentType', () => {
+ const Component = props =>
;
+ const { node } = createFormComponent({ schema: {}, tagName: Component });
+ expect(node.id).toBe('test');
+ });
+});
+
+describe('Nested forms', () => {
+ it('should call provided submit handler with form state', () => {
+ const innerOnSubmit = jest.fn();
+ const outerOnSubmit = jest.fn();
+ let innerRef;
+
+ class ArrayTemplateWithForm extends React.Component {
+ constructor(props) {
+ super(props);
+ innerRef = createRef();
+ }
+
+ render() {
+ const innerFormProps = {
+ schema: {},
+ onSubmit: innerOnSubmit,
+ };
+
+ return (
+
+
+
+
+
+ );
+ }
+ }
+
+ const outerFormProps = {
+ schema: {
+ type: 'array',
+ title: 'my list',
+ description: 'my description',
+ items: { type: 'string' },
+ },
+ formData: ['foo', 'bar'],
+ ArrayFieldTemplate: ArrayTemplateWithForm,
+ onSubmit: outerOnSubmit,
+ };
+ createFormComponent(outerFormProps);
+ const arrayForm = innerRef.current.querySelector('form');
+ const arraySubmit = arrayForm.querySelector('.array-form-submit');
+
+ arraySubmit.click();
+ expect(innerOnSubmit).toHaveBeenCalledTimes(1);
+ expect(outerOnSubmit).not.toHaveBeenCalled();
});
});
diff --git a/packages/oas-form/__tests__/NullField_test.js b/packages/oas-form/__tests__/NullField_test.js
index d37c5c8e6..b3372824c 100644
--- a/packages/oas-form/__tests__/NullField_test.js
+++ b/packages/oas-form/__tests__/NullField_test.js
@@ -40,7 +40,6 @@ describe('NullField', () => {
type: 'null',
},
formData: 3,
- noValidate: true,
});
submitForm(node);
diff --git a/packages/oas-form/__tests__/NumberField_test.js b/packages/oas-form/__tests__/NumberField_test.js
index eb32ba1b3..38a7271d5 100644
--- a/packages/oas-form/__tests__/NumberField_test.js
+++ b/packages/oas-form/__tests__/NumberField_test.js
@@ -69,7 +69,6 @@ describe('NumberField', () => {
const { node, onSubmit } = createFormComponent({
schema: { type: 'number' },
uiSchema,
- noValidate: true,
});
submitForm(node);
@@ -346,7 +345,6 @@ describe('NumberField', () => {
enum: [1, 2],
default: 1,
},
- noValidate: true,
});
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ formData: 1 }));
diff --git a/packages/oas-form/__tests__/ObjectField_test.js b/packages/oas-form/__tests__/ObjectField_test.js
index 1ab907594..3c175cfc1 100644
--- a/packages/oas-form/__tests__/ObjectField_test.js
+++ b/packages/oas-form/__tests__/ObjectField_test.js
@@ -1,7 +1,7 @@
import React from 'react';
import { Simulate } from 'react-dom/test-utils';
-import { createFormComponent, submitForm } from './test_utils';
+import { createFormComponent } from './test_utils';
describe('ObjectField', () => {
describe('schema', () => {
@@ -164,150 +164,6 @@ describe('ObjectField', () => {
});
});
- describe('fields ordering', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
- baz: { type: 'string' },
- qux: { type: 'string' },
- },
- };
-
- it('should use provided order', () => {
- const { node } = createFormComponent({
- schema,
- uiSchema: {
- 'ui:order': ['baz', 'qux', 'bar', 'foo'],
- },
- });
- const labels = [].map.call(node.querySelectorAll('.field > label'), l => l.textContent);
-
- expect(labels).toStrictEqual(['baz', 'qux', 'bar', 'foo']);
- });
-
- it('should insert unordered properties at wildcard position', () => {
- const { node } = createFormComponent({
- schema,
- uiSchema: {
- 'ui:order': ['baz', '*', 'foo'],
- },
- });
- const labels = [].map.call(node.querySelectorAll('.field > label'), l => l.textContent);
-
- expect(labels).toStrictEqual(['baz', 'bar', 'qux', 'foo']);
- });
-
- it('should use provided order also if order list contains extraneous properties', () => {
- const { node } = createFormComponent({
- schema,
- uiSchema: {
- 'ui:order': ['baz', 'qux', 'bar', 'wut?', 'foo', 'huh?'],
- },
- });
-
- const labels = [].map.call(node.querySelectorAll('.field > label'), l => l.textContent);
-
- expect(labels).toStrictEqual(['baz', 'qux', 'bar', 'foo']);
- });
-
- it('should throw when order list misses an existing property', () => {
- const { node } = createFormComponent({
- schema,
- uiSchema: {
- 'ui:order': ['baz', 'bar'],
- },
- });
-
- expect(node.querySelector('.config-error')).toHaveTextContent(/does not contain properties 'foo', 'qux'/);
- });
-
- it('should throw when more than one wildcard is present', () => {
- const { node } = createFormComponent({
- schema,
- uiSchema: {
- 'ui:order': ['baz', '*', 'bar', '*'],
- },
- });
-
- expect(node.querySelector('.config-error')).toHaveTextContent(/contains more than one wildcard/);
- });
-
- it('should order referenced schema definitions', () => {
- const refSchema = {
- definitions: {
- testdef: { type: 'string' },
- },
- type: 'object',
- properties: {
- foo: { $ref: '#/definitions/testdef' },
- bar: { $ref: '#/definitions/testdef' },
- },
- };
-
- const { node } = createFormComponent({
- schema: refSchema,
- uiSchema: {
- 'ui:order': ['bar', 'foo'],
- },
- });
- const labels = [].map.call(node.querySelectorAll('.field > label'), l => l.textContent);
-
- expect(labels).toStrictEqual(['bar', 'foo']);
- });
-
- it('should order referenced object schema definition properties', () => {
- const refSchema = {
- definitions: {
- testdef: {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
- },
- },
- },
- type: 'object',
- properties: {
- root: { $ref: '#/definitions/testdef' },
- },
- };
-
- const { node } = createFormComponent({
- schema: refSchema,
- uiSchema: {
- root: {
- 'ui:order': ['bar', 'foo'],
- },
- },
- });
- const labels = [].map.call(node.querySelectorAll('.field > label'), l => l.textContent);
-
- expect(labels).toStrictEqual(['bar', 'foo']);
- });
-
- it('should render the widget with the expected id', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
- },
- };
-
- const { node } = createFormComponent({
- schema,
- uiSchema: {
- 'ui:order': ['bar', 'foo'],
- },
- });
-
- const ids = [].map.call(node.querySelectorAll('input[type=text]'), node => node.id);
- expect(ids).toStrictEqual(['root_bar', 'root_foo']);
- });
- });
-
describe('Title', () => {
const TitleField = props =>
;
@@ -384,53 +240,6 @@ describe('ObjectField', () => {
expect(labels[1]).toHaveTextContent('CustomName');
});
- it('should not throw validation errors if additionalProperties is undefined', () => {
- const undefinedAPSchema = {
- ...schema,
- properties: { second: { type: 'string' } },
- };
- delete undefinedAPSchema.additionalProperties;
- const { node, onSubmit, onError } = createFormComponent({
- schema: undefinedAPSchema,
- formData: { nonschema: 1 },
- });
-
- submitForm(node);
- expect(onSubmit).toHaveBeenCalledWith(
- expect.objectContaining({
- formData: { nonschema: 1 },
- }),
- expect.anything()
- );
-
- expect(onError).not.toHaveBeenCalled();
- });
-
- it('should throw a validation error if additionalProperties is false', () => {
- const { node, onSubmit, onError } = createFormComponent({
- schema: {
- ...schema,
- additionalProperties: false,
- properties: { second: { type: 'string' } },
- },
- formData: { nonschema: 1 },
- });
- submitForm(node);
- expect(onSubmit).not.toHaveBeenCalled();
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'is an invalid additional property',
- name: 'additionalProperties',
- params: { additionalProperty: 'nonschema' },
- property: "['nonschema']",
- schemaPath: '#/additionalProperties',
- stack: "['nonschema'] is an invalid additional property",
- },
- ])
- );
- });
-
it('should still obey properties if additionalProperties is defined', () => {
const { node } = createFormComponent({
schema: {
diff --git a/packages/oas-form/__tests__/SchemaField_test.js b/packages/oas-form/__tests__/SchemaField_test.js
index 4d4413c7f..6b1d3d633 100644
--- a/packages/oas-form/__tests__/SchemaField_test.js
+++ b/packages/oas-form/__tests__/SchemaField_test.js
@@ -1,5 +1,4 @@
import React from 'react';
-import { Simulate } from 'react-dom/test-utils';
import SchemaField from '../src/components/fields/SchemaField';
import TitleField from '../src/components/fields/TitleField';
@@ -314,72 +313,4 @@ describe('SchemaField', () => {
expect(node.querySelector('#custom')).toHaveTextContent('A Foo field');
});
});
-
- describe('errors', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- },
- };
-
- const uiSchema = {
- 'ui:field': props => {
- const { uiSchema, ...fieldProps } = props;
- return ;
- },
- };
-
- function validate(formData, errors) {
- errors.addError('container');
- errors.foo.addError('test');
- return errors;
- }
-
- it('should render its own errors', () => {
- const { node } = createFormComponent({
- schema,
- uiSchema,
- validate,
- });
- Simulate.submit(node);
-
- const matches = node.querySelectorAll('form > .form-group > div > .error-detail .text-danger');
- expect(matches).toHaveLength(1);
- expect(matches[0]).toHaveTextContent('container');
- });
-
- it('should pass errors to child component', () => {
- const { node } = createFormComponent({
- schema,
- uiSchema,
- validate,
- });
- Simulate.submit(node);
-
- const matches = node.querySelectorAll('form .form-group .form-group .text-danger');
- expect(matches).toHaveLength(1);
- expect(matches[0]).toHaveTextContent('test');
- });
-
- describe('Custom error rendering', () => {
- const customStringWidget = props => {
- return {props.rawErrors}
;
- };
-
- it('should pass rawErrors down to custom widgets', () => {
- const { node } = createFormComponent({
- schema,
- uiSchema,
- validate,
- widgets: { BaseInput: customStringWidget },
- });
- Simulate.submit(node);
-
- const matches = node.querySelectorAll('.custom-text-widget');
- expect(matches).toHaveLength(1);
- expect(matches[0]).toHaveTextContent('test');
- });
- });
- });
});
diff --git a/packages/oas-form/__tests__/StringField_test.js b/packages/oas-form/__tests__/StringField_test.js
index 2d32b95c2..2873d2a51 100644
--- a/packages/oas-form/__tests__/StringField_test.js
+++ b/packages/oas-form/__tests__/StringField_test.js
@@ -98,7 +98,6 @@ describe('StringField', () => {
it('should default submit value to undefined', () => {
const { node, onSubmit } = createFormComponent({
schema: { type: 'string' },
- noValidate: true,
});
submitForm(node);
@@ -671,36 +670,6 @@ describe('StringField', () => {
expect(node.querySelector('[type=datetime-local]').id).toBe('root');
});
- it('should reject an invalid entered datetime', () => {
- const { node, onChange } = createFormComponent({
- schema: {
- type: 'string',
- format: 'date-time',
- },
- liveValidate: true,
- });
-
- Simulate.change(node.querySelector('[type=datetime-local]'), {
- target: { value: 'invalid' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: { __errors: ['should be string'] },
- errors: [
- {
- message: 'should be string',
- name: 'type',
- params: { type: 'string' },
- property: '',
- schemaPath: '#/type',
- stack: 'should be string',
- },
- ],
- })
- );
- });
-
it('should render customized DateTimeWidget', () => {
const { node } = createFormComponent({
schema: {
@@ -754,7 +723,6 @@ describe('StringField', () => {
default: datetime,
},
uiSchema,
- noValidate: true,
});
submitForm(node);
expect(onSubmit).toHaveBeenLastCalledWith(
@@ -792,7 +760,6 @@ describe('StringField', () => {
format: 'date',
},
formData: datetime,
- noValidate: true,
});
submitForm(node);
expect(onSubmit).toHaveBeenLastCalledWith(
@@ -816,21 +783,18 @@ describe('StringField', () => {
});
it('should accept a valid entered date', () => {
- const { node, onError, onChange } = createFormComponent({
+ const { node, onChange } = createFormComponent({
schema: {
type: 'string',
format: 'date',
},
uiSchema,
- liveValidate: true,
});
Simulate.change(node.querySelector('[type=date]'), {
target: { value: '2012-12-12' },
});
- expect(onError).not.toHaveBeenCalled();
-
expect(onChange).toHaveBeenLastCalledWith(
expect.objectContaining({
formData: '2012-12-12',
@@ -838,37 +802,6 @@ describe('StringField', () => {
);
});
- it('should reject an invalid entered date', () => {
- const { node, onChange } = createFormComponent({
- schema: {
- type: 'string',
- format: 'date',
- },
- uiSchema,
- liveValidate: true,
- });
-
- Simulate.change(node.querySelector('[type=date]'), {
- target: { value: 'invalid' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: { __errors: ['should match format "date"'] },
- errors: [
- {
- message: 'should match format "date"',
- name: 'format',
- params: { format: 'date' },
- property: '',
- schemaPath: '#/format',
- stack: 'should match format "date"',
- },
- ],
- })
- );
- });
-
it('should render customized DateWidget', () => {
const { node } = createFormComponent({
schema: {
@@ -1301,20 +1234,6 @@ describe('StringField', () => {
]);
});
- it('should accept a valid date', () => {
- const { onError } = createFormComponent({
- schema: {
- type: 'string',
- format: 'date',
- },
- uiSchema,
- liveValidate: true,
- formData: '2012-12-12',
- });
-
- expect(onError).not.toHaveBeenCalled();
- });
-
it('should throw on invalid date', () => {
expect(() => {
createFormComponent({
@@ -1323,7 +1242,6 @@ describe('StringField', () => {
format: 'date',
},
uiSchema,
- liveValidate: true,
formData: '2012-1212',
});
}).toThrow('Unable to parse date 2012-1212');
@@ -1500,36 +1418,6 @@ describe('StringField', () => {
expect(node.querySelector('[type=email]').id).toBe('root');
});
- it('should reject an invalid entered email', () => {
- const { node, onChange } = createFormComponent({
- schema: {
- type: 'string',
- format: 'email',
- },
- liveValidate: true,
- });
-
- Simulate.change(node.querySelector('[type=email]'), {
- target: { value: 'invalid' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: { __errors: ['should match format "email"'] },
- errors: [
- {
- message: 'should match format "email"',
- name: 'format',
- params: { format: 'email' },
- property: '',
- schemaPath: '#/format',
- stack: 'should match format "email"',
- },
- ],
- })
- );
- });
-
it('should render customized EmailWidget', () => {
const { node } = createFormComponent({
schema: {
@@ -1648,36 +1536,6 @@ describe('StringField', () => {
expect(node.querySelector('[type=url]').id).toBe('root');
});
- it('should reject an invalid entered url', () => {
- const { node, onChange } = createFormComponent({
- schema: {
- type: 'string',
- format: 'uri',
- },
- liveValidate: true,
- });
-
- Simulate.change(node.querySelector('[type=url]'), {
- target: { value: 'invalid' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: { __errors: ['should match format "uri"'] },
- errors: [
- {
- message: 'should match format "uri"',
- name: 'format',
- params: { format: 'uri' },
- property: '',
- schemaPath: '#/format',
- stack: 'should match format "uri"',
- },
- ],
- })
- );
- });
-
it('should render customized URLWidget', () => {
const { node } = createFormComponent({
schema: {
@@ -1766,37 +1624,6 @@ describe('StringField', () => {
expect(node.querySelector('[type=color]').id).toBe('root');
});
- it('should reject an invalid entered color', () => {
- const { node, onChange } = createFormComponent({
- schema: {
- type: 'string',
- format: 'color',
- },
- uiSchema,
- liveValidate: true,
- });
-
- Simulate.change(node.querySelector('[type=color]'), {
- target: { value: 'invalid' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: { __errors: ['should match format "color"'] },
- errors: [
- {
- message: 'should match format "color"',
- name: 'format',
- params: { format: 'color' },
- property: '',
- schemaPath: '#/format',
- stack: 'should match format "color"',
- },
- ],
- })
- );
- });
-
it('should render customized ColorWidget', () => {
const { node } = createFormComponent({
schema: {
diff --git a/packages/oas-form/__tests__/anyOf_test.js b/packages/oas-form/__tests__/anyOf_test.js
index 17fc33311..309aebd6a 100644
--- a/packages/oas-form/__tests__/anyOf_test.js
+++ b/packages/oas-form/__tests__/anyOf_test.js
@@ -357,33 +357,6 @@ describe('anyOf', () => {
expect(node.querySelectorAll('#custom-anyof-field')).toHaveLength(1);
});
- it('should select the correct field when the form is rendered from existing data', () => {
- const schema = {
- type: 'object',
- properties: {
- userId: {
- anyOf: [
- {
- type: 'number',
- },
- {
- type: 'string',
- },
- ],
- },
- },
- };
-
- const { node } = createFormComponent({
- schema,
- formData: {
- userId: 'foobarbaz',
- },
- });
-
- expect(node.querySelector('select').value).toBe('1');
- });
-
it.skip('should select the correct field when the formData property is updated', () => {
const schema = {
type: 'object',
diff --git a/packages/oas-form/__tests__/oneOf_test.js b/packages/oas-form/__tests__/oneOf_test.js
index 929185764..f4ac08201 100644
--- a/packages/oas-form/__tests__/oneOf_test.js
+++ b/packages/oas-form/__tests__/oneOf_test.js
@@ -351,33 +351,6 @@ describe('oneOf', () => {
expect(node.querySelectorAll('#custom-oneof-field')).toHaveLength(1);
});
- it('should select the correct field when the form is rendered from existing data', () => {
- const schema = {
- type: 'object',
- properties: {
- userId: {
- oneOf: [
- {
- type: 'number',
- },
- {
- type: 'string',
- },
- ],
- },
- },
- };
-
- const { node } = createFormComponent({
- schema,
- formData: {
- userId: 'foobarbaz',
- },
- });
-
- expect(node.querySelector('select').value).toBe('1');
- });
-
it.skip('should select the correct field when the formData property is updated', () => {
const schema = {
type: 'object',
diff --git a/packages/oas-form/__tests__/test_utils.js b/packages/oas-form/__tests__/test_utils.js
index b191738c2..3594268c5 100644
--- a/packages/oas-form/__tests__/test_utils.js
+++ b/packages/oas-form/__tests__/test_utils.js
@@ -9,11 +9,11 @@ import Form from '../src';
export function createComponent(Component, props) {
const onChange = jest.fn();
- const onError = jest.fn();
const onSubmit = jest.fn();
- const comp = renderIntoDocument( );
+ const comp = renderIntoDocument( );
const node = findDOMNode(comp);
- return { comp, node, onChange, onError, onSubmit };
+
+ return { comp, node, onChange, onSubmit };
}
export function createFormComponent(props) {
diff --git a/packages/oas-form/__tests__/utils_test.js b/packages/oas-form/__tests__/utils_test.js
index d780eb0b2..f368debec 100644
--- a/packages/oas-form/__tests__/utils_test.js
+++ b/packages/oas-form/__tests__/utils_test.js
@@ -3,7 +3,6 @@ import React from 'react';
import {
ADDITIONAL_PROPERTY_FLAG,
asNumber,
- orderProperties,
dataURItoBlob,
deepEquals,
getDefaultFormState,
@@ -22,9 +21,7 @@ import {
shouldRender,
toDateString,
toIdSchema,
- toPathSchema,
guessType,
- mergeSchemas,
} from '../src/utils';
describe('utils', () => {
@@ -675,41 +672,6 @@ describe('utils', () => {
},
});
});
-
- it('should populate defaults for oneOf + dependencies', () => {
- const schema = {
- oneOf: [
- {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- },
- },
- },
- ],
- dependencies: {
- name: {
- oneOf: [
- {
- properties: {
- name: {
- type: 'string',
- },
- grade: {
- default: 'A',
- },
- },
- },
- ],
- },
- },
- };
- expect(getDefaultFormState(schema, { name: 'Name' })).toStrictEqual({
- name: 'Name',
- grade: 'A',
- });
- });
});
describe('defaults with anyOf', () => {
@@ -755,362 +717,6 @@ describe('utils', () => {
},
});
});
-
- it('should populate defaults for anyOf + dependencies', () => {
- const schema = {
- anyOf: [
- {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- },
- },
- },
- ],
- dependencies: {
- name: {
- oneOf: [
- {
- properties: {
- name: {
- type: 'string',
- },
- grade: {
- type: 'string',
- default: 'A',
- },
- },
- },
- ],
- },
- },
- };
- expect(getDefaultFormState(schema, { name: 'Name' })).toStrictEqual({
- name: 'Name',
- grade: 'A',
- });
- });
- });
-
- describe('with dependencies', () => {
- it('should populate defaults for dependencies', () => {
- const schema = {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- },
- },
- dependencies: {
- name: {
- oneOf: [
- {
- properties: {
- name: {
- type: 'string',
- },
- grade: {
- type: 'string',
- default: 'A',
- },
- },
- },
- ],
- },
- },
- };
- expect(getDefaultFormState(schema, { name: 'Name' })).toStrictEqual({
- name: 'Name',
- grade: 'A',
- });
- });
-
- it('should populate defaults for nested dependencies', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- },
- },
- dependencies: {
- name: {
- oneOf: [
- {
- properties: {
- name: {
- type: 'string',
- },
- grade: {
- type: 'string',
- default: 'A',
- },
- },
- },
- ],
- },
- },
- },
- },
- };
- expect(getDefaultFormState(schema, { foo: { name: 'Name' } })).toStrictEqual({
- foo: {
- name: 'Name',
- grade: 'A',
- },
- });
- });
-
- it('should populate defaults for nested dependencies in arrays', () => {
- const schema = {
- type: 'array',
- items: {
- properties: {
- foo: {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- },
- },
- dependencies: {
- name: {
- oneOf: [
- {
- properties: {
- name: {
- type: 'string',
- },
- grade: {
- type: 'string',
- default: 'A',
- },
- },
- },
- ],
- },
- },
- },
- },
- },
- };
- expect(getDefaultFormState(schema, [{ foo: { name: 'Name' } }])).toStrictEqual([
- {
- foo: {
- name: 'Name',
- grade: 'A',
- },
- },
- ]);
- });
-
- it('should populate defaults for nested dependencies in arrays when matching enum values in oneOf', () => {
- const schema = {
- type: 'array',
- items: {
- properties: {
- foo: {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- },
- },
- dependencies: {
- name: {
- oneOf: [
- {
- properties: {
- name: {
- enum: ['first'],
- },
- grade: {
- type: 'string',
- default: 'A',
- },
- },
- },
- {
- properties: {
- name: {
- enum: ['second'],
- },
- grade: {
- type: 'string',
- default: 'B',
- },
- },
- },
- ],
- },
- },
- },
- },
- },
- };
- expect(
- getDefaultFormState(schema, [
- { foo: { name: 'first' } },
- { foo: { name: 'second' } },
- { foo: { name: 'third' } },
- ])
- ).toStrictEqual([
- {
- foo: {
- name: 'first',
- grade: 'A',
- },
- },
- {
- foo: {
- name: 'second',
- grade: 'B',
- },
- },
- {
- foo: {
- name: 'third',
- },
- },
- ]);
- });
-
- it('should populate defaults for nested oneOf + dependencies', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: {
- oneOf: [
- {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- },
- },
- },
- ],
- dependencies: {
- name: {
- oneOf: [
- {
- properties: {
- name: {
- type: 'string',
- },
- grade: {
- type: 'string',
- default: 'A',
- },
- },
- },
- ],
- },
- },
- },
- },
- };
- expect(getDefaultFormState(schema, { foo: { name: 'Name' } })).toStrictEqual({
- foo: {
- name: 'Name',
- grade: 'A',
- },
- });
- });
-
- it('should populate defaults for nested dependencies when formData passed to computeDefaults is undefined', () => {
- const schema = {
- type: 'object',
- properties: {
- can_1: {
- type: 'object',
- properties: {
- phy: {
- title: 'Physical',
- description: 'XYZ',
- type: 'object',
- properties: {
- bit_rate_cfg_mode: {
- title: 'Sub title',
- description: 'XYZ',
- type: 'integer',
- default: 0,
- },
- },
- dependencies: {
- bit_rate_cfg_mode: {
- oneOf: [
- {
- properties: {
- bit_rate_cfg_mode: {
- enum: [0],
- },
- },
- },
- ],
- },
- },
- },
- },
- },
- },
- };
- expect(getDefaultFormState(schema, undefined)).toStrictEqual({
- can_1: {
- phy: {
- bit_rate_cfg_mode: 0,
- },
- },
- });
- });
-
- it('should not crash for defaults for nested dependencies when formData passed to computeDefaults is null', () => {
- const schema = {
- type: 'object',
- properties: {
- can_1: {
- type: 'object',
- properties: {
- phy: {
- title: 'Physical',
- description: 'XYZ',
- type: 'object',
- properties: {
- bit_rate_cfg_mode: {
- title: 'Sub title',
- description: 'XYZ',
- type: 'integer',
- default: 0,
- },
- },
- dependencies: {
- bit_rate_cfg_mode: {
- oneOf: [
- {
- properties: {
- bit_rate_cfg_mode: {
- enum: [0],
- },
- },
- },
- ],
- },
- },
- },
- },
- },
- },
- };
- expect(getDefaultFormState(schema, { can_1: { phy: null } })).toStrictEqual({
- can_1: {
- phy: null,
- },
- });
- });
});
describe('with schema keys not defined in the formData', () => {
@@ -1166,32 +772,6 @@ describe('utils', () => {
});
});
- describe('orderProperties()', () => {
- it('should remove from order elements that are not in properties', () => {
- const properties = ['foo', 'baz'];
- const order = ['foo', 'bar', 'baz', 'qux'];
- expect(orderProperties(properties, order)).toStrictEqual(['foo', 'baz']);
- });
-
- it('should order properties according to the order', () => {
- const properties = ['bar', 'foo'];
- const order = ['foo', 'bar'];
- expect(orderProperties(properties, order)).toStrictEqual(['foo', 'bar']);
- });
-
- it('should replace * with properties that are absent in order', () => {
- const properties = ['foo', 'bar', 'baz'];
- const order = ['*', 'foo'];
- expect(orderProperties(properties, order)).toStrictEqual(['bar', 'baz', 'foo']);
- });
-
- it('should handle more complex ordering case correctly', () => {
- const properties = ['foo', 'baz', 'qux', 'bar'];
- const order = ['quux', 'foo', '*', 'corge', 'baz'];
- expect(orderProperties(properties, order)).toStrictEqual(['foo', 'qux', 'bar', 'baz']);
- });
- });
-
describe('isConstant', () => {
it('should return false when neither enum nor const is defined', () => {
const schema = {};
@@ -1483,121 +1063,6 @@ describe('utils', () => {
});
});
- describe('mergeSchemas()', () => {
- it("shouldn't mutate the provided objects", () => {
- const obj1 = { a: 1 };
- mergeSchemas(obj1, { b: 2 });
- expect(obj1).toStrictEqual({ a: 1 });
- });
-
- it('should merge two one-level deep objects', () => {
- expect(mergeSchemas({ a: 1 }, { b: 2 })).toStrictEqual({ a: 1, b: 2 });
- });
-
- it('should override the first object with the values from the second', () => {
- expect(mergeSchemas({ a: 1 }, { a: 2 })).toStrictEqual({ a: 2 });
- });
-
- it('should override non-existing values of the first object with the values from the second', () => {
- expect(mergeSchemas({ a: { b: undefined } }, { a: { b: { c: 1 } } })).toStrictEqual({ a: { b: { c: 1 } } });
- });
-
- it('should recursively merge deeply nested objects', () => {
- const obj1 = {
- a: 1,
- b: {
- c: 3,
- d: [1, 2, 3],
- e: { f: { g: 1 } },
- },
- c: 2,
- };
- const obj2 = {
- a: 1,
- b: {
- d: [3, 2, 1],
- e: { f: { h: 2 } },
- g: 1,
- },
- c: 3,
- };
- const expected = {
- a: 1,
- b: {
- c: 3,
- d: [3, 2, 1],
- e: { f: { g: 1, h: 2 } },
- g: 1,
- },
- c: 3,
- };
- expect(mergeSchemas(obj1, obj2)).toStrictEqual(expected);
- });
-
- it('should recursively merge File objects', () => {
- const file = new File(['test'], 'test.txt');
- const obj1 = {
- a: {},
- };
- const obj2 = {
- a: file,
- };
- expect(mergeSchemas(obj1, obj2).a).toBeInstanceOf(File);
- });
-
- describe('arrays', () => {
- it('should not concat arrays', () => {
- const obj1 = { a: [1] };
- const obj2 = { a: [2] };
-
- expect(mergeSchemas(obj1, obj2)).toStrictEqual({ a: [2] });
- });
-
- it("should concat arrays under 'required' keyword", () => {
- const obj1 = { type: 'object', required: [1] };
- const obj2 = { type: 'object', required: [2] };
-
- expect(mergeSchemas(obj1, obj2)).toStrictEqual({
- type: 'object',
- required: [1, 2],
- });
- });
-
- it("should concat arrays under 'required' keyword when one of the schemas is an object type", () => {
- const obj1 = { type: 'object', required: [1] };
- const obj2 = { required: [2] };
-
- expect(mergeSchemas(obj1, obj2)).toStrictEqual({
- type: 'object',
- required: [1, 2],
- });
- });
-
- it("should concat nested arrays under 'required' keyword", () => {
- const obj1 = { a: { type: 'object', required: [1] } };
- const obj2 = { a: { type: 'object', required: [2] } };
-
- expect(mergeSchemas(obj1, obj2)).toStrictEqual({
- a: { type: 'object', required: [1, 2] },
- });
- });
-
- it("should not include duplicate values when concatting arrays under 'required' keyword", () => {
- const obj1 = { type: 'object', required: [1] };
- const obj2 = { type: 'object', required: [1] };
-
- expect(mergeSchemas(obj1, obj2)).toStrictEqual({ type: 'object', required: [1] });
- });
-
- it("should not concat arrays under 'required' keyword that are not under an object type", () => {
- const obj1 = { required: [1] };
- const obj2 = { required: [2] };
-
- expect(mergeSchemas(obj1, obj2)).toStrictEqual({ required: [2] });
- });
- });
- });
-
describe('retrieveSchema()', () => {
it("should 'resolve' a schema which contains definitions", () => {
const schema = { $ref: '#/definitions/address' };
@@ -1731,558 +1196,18 @@ describe('utils', () => {
it('should priorize local definitions over foreign ones', () => {
const schema = {
- $ref: '#/definitions/address',
- title: 'foo',
- };
- const address = {
- type: 'string',
- title: 'bar',
- };
- const definitions = { address };
-
- expect(retrieveSchema(schema, { definitions })).toStrictEqual({
- ...address,
- title: 'foo',
- });
- });
-
- describe('property dependencies', () => {
- describe('false condition', () => {
- it('should not add required properties', () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string' },
- b: { type: 'integer' },
- },
- required: ['a'],
- dependencies: {
- a: ['b'],
- },
- };
- const definitions = {};
- const formData = {};
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string' },
- b: { type: 'integer' },
- },
- required: ['a'],
- });
- });
- });
-
- describe('true condition', () => {
- describe('when required is not defined', () => {
- it('should define required properties', () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string' },
- b: { type: 'integer' },
- },
- dependencies: {
- a: ['b'],
- },
- };
- const definitions = {};
- const formData = { a: '1' };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string' },
- b: { type: 'integer' },
- },
- required: ['b'],
- });
- });
- });
-
- describe('when required is defined', () => {
- it('should concat required properties', () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string' },
- b: { type: 'integer' },
- },
- required: ['a'],
- dependencies: {
- a: ['b'],
- },
- };
- const definitions = {};
- const formData = { a: '1' };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string' },
- b: { type: 'integer' },
- },
- required: ['a', 'b'],
- });
- });
- });
- });
- });
-
- describe('schema dependencies', () => {
- describe('conditional', () => {
- describe('false condition', () => {
- it('should not modify properties', () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string' },
- },
- dependencies: {
- a: {
- properties: {
- b: { type: 'integer' },
- },
- },
- },
- };
- const definitions = {};
- const formData = {};
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string' },
- },
- });
- });
- });
-
- describe('true condition', () => {
- it('should add properties', () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string' },
- },
- dependencies: {
- a: {
- properties: {
- b: { type: 'integer' },
- },
- },
- },
- };
- const definitions = {};
- const formData = { a: '1' };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string' },
- b: { type: 'integer' },
- },
- });
- });
-
- it('should concat required properties', () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string' },
- b: { type: 'integer' },
- },
- required: ['a'],
- dependencies: {
- a: {
- properties: {
- a: { type: 'string' },
- },
- required: ['b'],
- },
- },
- };
- const definitions = {};
- const formData = { a: '1' };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string' },
- b: { type: 'integer' },
- },
- required: ['a', 'b'],
- });
- });
-
- it("should not concat enum properties, but should concat 'required' properties", () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string', enum: ['FOO', 'BAR', 'BAZ'] },
- b: { type: 'string', enum: ['GREEN', 'BLUE', 'RED'] },
- },
- required: ['a'],
- dependencies: {
- a: {
- properties: {
- a: { enum: ['FOO'] },
- b: { enum: ['BLUE'] },
- },
- required: ['a', 'b'],
- },
- },
- };
- const definitions = {};
- const formData = { a: 'FOO' };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string', enum: ['FOO'] },
- b: { type: 'string', enum: ['BLUE'] },
- },
- required: ['a', 'b'],
- });
- });
- });
-
- describe('with $ref in dependency', () => {
- it('should retrieve referenced schema', () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string' },
- },
- dependencies: {
- a: {
- $ref: '#/definitions/needsB',
- },
- },
- };
- const definitions = {
- needsB: {
- properties: {
- b: { type: 'integer' },
- },
- },
- };
- const formData = { a: '1' };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string' },
- b: { type: 'integer' },
- },
- });
- });
- });
-
- describe('with $ref in oneOf', () => {
- it('should retrieve referenced schemas', () => {
- const schema = {
- type: 'object',
- properties: {
- a: { enum: ['typeA', 'typeB'] },
- },
- dependencies: {
- a: {
- oneOf: [{ $ref: '#/definitions/needsA' }, { $ref: '#/definitions/needsB' }],
- },
- },
- };
- const definitions = {
- needsA: {
- properties: {
- a: { enum: ['typeA'] },
- b: { type: 'number' },
- },
- },
- needsB: {
- properties: {
- a: { enum: ['typeB'] },
- c: { type: 'boolean' },
- },
- },
- };
- const formData = { a: 'typeB' };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { enum: ['typeA', 'typeB'] },
- c: { type: 'boolean' },
- },
- });
- });
- });
- });
-
- describe('dynamic', () => {
- describe('false condition', () => {
- it('should not modify properties', () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string' },
- },
- dependencies: {
- a: {
- oneOf: [
- {
- properties: {
- a: { enum: ['int'] },
- b: { type: 'integer' },
- },
- },
- {
- properties: {
- a: { enum: ['bool'] },
- b: { type: 'boolean' },
- },
- },
- ],
- },
- },
- };
- const definitions = {};
- const formData = {};
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string' },
- },
- });
- });
- });
-
- describe('true condition', () => {
- it("should add 'first' properties given 'first' data", () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string', enum: ['int', 'bool'] },
- },
- dependencies: {
- a: {
- oneOf: [
- {
- properties: {
- a: { enum: ['int'] },
- b: { type: 'integer' },
- },
- },
- {
- properties: {
- a: { enum: ['bool'] },
- b: { type: 'boolean' },
- },
- },
- ],
- },
- },
- };
- const definitions = {};
- const formData = { a: 'int' };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string', enum: ['int', 'bool'] },
- b: { type: 'integer' },
- },
- });
- });
-
- it("should add 'second' properties given 'second' data", () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string', enum: ['int', 'bool'] },
- },
- dependencies: {
- a: {
- oneOf: [
- {
- properties: {
- a: { enum: ['int'] },
- b: { type: 'integer' },
- },
- },
- {
- properties: {
- a: { enum: ['bool'] },
- b: { type: 'boolean' },
- },
- },
- ],
- },
- },
- };
- const definitions = {};
- const formData = { a: 'bool' };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string', enum: ['int', 'bool'] },
- b: { type: 'boolean' },
- },
- });
- });
-
- describe('showing/hiding nested dependencies', () => {
- const schema = {
- type: 'object',
- dependencies: {
- employee_accounts: {
- oneOf: [
- {
- properties: {
- employee_accounts: {
- const: true,
- },
- update_absences: {
- title: 'Update Absences',
- type: 'string',
- oneOf: [
- {
- title: 'Both',
- const: 'BOTH',
- },
- ],
- },
- },
- },
- ],
- },
- update_absences: {
- oneOf: [
- {
- properties: {
- permitted_extension: {
- title: 'Permitted Extension',
- type: 'integer',
- },
- update_absences: {
- const: 'BOTH',
- },
- },
- },
- {
- properties: {
- permitted_extension: {
- title: 'Permitted Extension',
- type: 'integer',
- },
- update_absences: {
- const: 'MEDICAL_ONLY',
- },
- },
- },
- {
- properties: {
- permitted_extension: {
- title: 'Permitted Extension',
- type: 'integer',
- },
- update_absences: {
- const: 'NON_MEDICAL_ONLY',
- },
- },
- },
- ],
- },
- },
- properties: {
- employee_accounts: {
- type: 'boolean',
- title: 'Employee Accounts',
- },
- },
- };
- const definitions = {};
-
- it('should not include nested dependencies that should be hidden', () => {
- const formData = {
- employee_accounts: false,
- update_absences: 'BOTH',
- };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- employee_accounts: {
- type: 'boolean',
- title: 'Employee Accounts',
- },
- },
- });
- });
-
- it('should include nested dependencies that should not be hidden', () => {
- const formData = {
- employee_accounts: true,
- update_absences: 'BOTH',
- };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- employee_accounts: {
- type: 'boolean',
- title: 'Employee Accounts',
- },
- permitted_extension: {
- title: 'Permitted Extension',
- type: 'integer',
- },
- update_absences: {
- title: 'Update Absences',
- type: 'string',
- oneOf: [
- {
- title: 'Both',
- const: 'BOTH',
- },
- ],
- },
- },
- });
- });
- });
- });
-
- describe('with $ref in dependency', () => {
- it('should retrieve the referenced schema', () => {
- const schema = {
- type: 'object',
- properties: {
- a: { type: 'string', enum: ['int', 'bool'] },
- },
- dependencies: {
- a: {
- $ref: '#/definitions/typedInput',
- },
- },
- };
- const definitions = {
- typedInput: {
- oneOf: [
- {
- properties: {
- a: { enum: ['int'] },
- b: { type: 'integer' },
- },
- },
- {
- properties: {
- a: { enum: ['bool'] },
- b: { type: 'boolean' },
- },
- },
- ],
- },
- };
- const formData = { a: 'bool' };
- expect(retrieveSchema(schema, { definitions }, formData)).toStrictEqual({
- type: 'object',
- properties: {
- a: { type: 'string', enum: ['int', 'bool'] },
- b: { type: 'boolean' },
- },
- });
- });
- });
+ $ref: '#/definitions/address',
+ title: 'foo',
+ };
+ const address = {
+ type: 'string',
+ title: 'bar',
+ };
+ const definitions = { address };
+
+ expect(retrieveSchema(schema, { definitions })).toStrictEqual({
+ ...address,
+ title: 'foo',
});
});
@@ -2524,774 +1449,113 @@ describe('utils', () => {
type: 'string',
},
},
- required: ['id'],
- },
- },
- };
- expect(toIdSchema(schema)).toStrictEqual({
- $id: 'root',
- metadata: {
- $id: 'root_metadata',
- id: { $id: 'root_metadata_id' },
- },
- });
- });
-
- it('should return an idSchema for array item objects', () => {
- const schema = {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- },
- },
- };
-
- expect(toIdSchema(schema)).toStrictEqual({
- $id: 'root',
- foo: { $id: 'root_foo' },
- });
- });
-
- it('should retrieve referenced schema definitions', () => {
- const schema = {
- definitions: {
- testdef: {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
- },
- },
- },
- $ref: '#/definitions/testdef',
- };
-
- expect(toIdSchema(schema, undefined, schema)).toStrictEqual({
- $id: 'root',
- foo: { $id: 'root_foo' },
- bar: { $id: 'root_bar' },
- });
- });
-
- it('should return an idSchema for property dependencies', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- },
- dependencies: {
- foo: {
- properties: {
- bar: { type: 'string' },
- },
- },
- },
- };
- const formData = {
- foo: 'test',
- };
-
- expect(toIdSchema(schema, undefined, schema, formData)).toStrictEqual({
- $id: 'root',
- foo: { $id: 'root_foo' },
- bar: { $id: 'root_bar' },
- });
- });
-
- it('should return an idSchema for nested property dependencies', () => {
- const schema = {
- type: 'object',
- properties: {
- obj: {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- },
- dependencies: {
- foo: {
- properties: {
- bar: { type: 'string' },
- },
- },
- },
- },
- },
- };
- const formData = {
- obj: {
- foo: 'test',
- },
- };
-
- expect(toIdSchema(schema, undefined, schema, formData)).toStrictEqual({
- $id: 'root',
- obj: {
- $id: 'root_obj',
- foo: { $id: 'root_obj_foo' },
- bar: { $id: 'root_obj_bar' },
- },
- });
- });
-
- it('should return an idSchema for unmet property dependencies', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- },
- dependencies: {
- foo: {
- properties: {
- bar: { type: 'string' },
- },
- },
- },
- };
-
- const formData = {};
-
- expect(toIdSchema(schema, undefined, schema, formData)).toStrictEqual({
- $id: 'root',
- foo: { $id: 'root_foo' },
- });
- });
-
- it('should handle idPrefix parameter', () => {
- const schema = {
- definitions: {
- testdef: {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
- },
- },
- },
- $ref: '#/definitions/testdef',
- };
-
- expect(toIdSchema(schema, undefined, schema, {}, 'rjsf')).toStrictEqual({
- $id: 'rjsf',
- foo: { $id: 'rjsf_foo' },
- bar: { $id: 'rjsf_bar' },
- });
- });
-
- it('should handle null form data for object schemas', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
- },
- };
- const formData = null;
- const result = toIdSchema(schema, null, {}, formData, 'rjsf');
-
- expect(result).toStrictEqual({
- $id: 'rjsf',
- foo: { $id: 'rjsf_foo' },
- bar: { $id: 'rjsf_bar' },
- });
- });
-
- it('should handle circular referencing', () => {
- const treeSchema = {
- properties: {},
- };
- treeSchema.properties.tree = treeSchema;
- const rootSchema = {
- definitions: {},
- properties: {
- tree: treeSchema,
- },
- type: 'object',
- };
-
- const result = toIdSchema(treeSchema, null, rootSchema);
-
- expect(result).toStrictEqual({
- $id: 'root',
- });
- });
- });
-
- describe('toPathSchema', () => {
- it('should return a pathSchema for root field', () => {
- const schema = { type: 'string' };
-
- expect(toPathSchema(schema)).toStrictEqual({ $name: '' });
- });
-
- it('should return a pathSchema for nested objects', () => {
- const schema = {
- type: 'object',
- properties: {
- level1: {
- type: 'object',
- properties: {
- level2: { type: 'string' },
- },
- },
- },
- };
-
- expect(toPathSchema(schema)).toStrictEqual({
- $name: '',
- level1: {
- $name: 'level1',
- level2: { $name: 'level1.level2' },
- },
- });
- });
-
- it('should return a pathSchema for a schema with dependencies', () => {
- const schema = {
- type: 'object',
- properties: {
- list: {
- title: 'list',
- type: 'array',
- items: {
- type: 'object',
- properties: {
- a: { type: 'string' },
- b: { type: 'string' },
- },
- dependencies: {
- b: {
- properties: {
- c: {
- type: 'string',
- },
- },
- },
- },
- },
- },
- },
- };
-
- const formData = {
- list: [
- {
- a: 'a1',
- b: 'b1',
- c: 'c1',
- },
- {
- a: 'a2',
- },
- {
- a: 'a2',
- c: 'c2',
- },
- ],
- };
-
- expect(toPathSchema(schema, '', schema, formData)).toStrictEqual({
- $name: '',
- list: {
- $name: 'list',
- 0: {
- $name: 'list.0',
- a: {
- $name: 'list.0.a',
- },
- b: {
- $name: 'list.0.b',
- },
- c: {
- $name: 'list.0.c',
- },
- },
- 1: {
- $name: 'list.1',
- a: {
- $name: 'list.1.a',
- },
- b: {
- $name: 'list.1.b',
- },
- },
- 2: {
- $name: 'list.2',
- a: {
- $name: 'list.2.a',
- },
- b: {
- $name: 'list.2.b',
- },
- },
- },
- });
- });
-
- it('should return a pathSchema for a schema with references', () => {
- const schema = {
- definitions: {
- address: {
- type: 'object',
- properties: {
- street_address: {
- type: 'string',
- },
- city: {
- type: 'string',
- },
- state: {
- type: 'string',
- },
- },
- required: ['street_address', 'city', 'state'],
- },
- },
- type: 'object',
- properties: {
- billing_address: {
- title: 'Billing address',
- $ref: '#/definitions/address',
+ required: ['id'],
},
},
};
-
- const formData = {
- billing_address: {
- street_address: '21, Jump Street',
- city: 'Babel',
- state: 'Neverland',
+ expect(toIdSchema(schema)).toStrictEqual({
+ $id: 'root',
+ metadata: {
+ $id: 'root_metadata',
+ id: { $id: 'root_metadata_id' },
},
- };
+ });
+ });
- expect(toPathSchema(schema, '', schema, formData)).toStrictEqual({
- $name: '',
- billing_address: {
- $name: 'billing_address',
- city: {
- $name: 'billing_address.city',
- },
- state: {
- $name: 'billing_address.state',
- },
- street_address: {
- $name: 'billing_address.street_address',
+ it('should return an idSchema for array item objects', () => {
+ const schema = {
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ foo: { type: 'string' },
},
},
+ };
+
+ expect(toIdSchema(schema)).toStrictEqual({
+ $id: 'root',
+ foo: { $id: 'root_foo' },
});
});
- it('should return a pathSchema for a schema with references in an array item', () => {
+ it('should retrieve referenced schema definitions', () => {
const schema = {
definitions: {
- address: {
+ testdef: {
type: 'object',
properties: {
- street_address: {
- type: 'string',
- },
- city: {
- type: 'string',
- },
- state: {
- type: 'string',
- },
- },
- required: ['street_address', 'city', 'state'],
- },
- },
- type: 'object',
- properties: {
- address_list: {
- title: 'Address list',
- type: 'array',
- items: {
- $ref: '#/definitions/address',
+ foo: { type: 'string' },
+ bar: { type: 'string' },
},
},
},
+ $ref: '#/definitions/testdef',
};
- const formData = {
- address_list: [
- {
- street_address: '21, Jump Street',
- city: 'Babel',
- state: 'Neverland',
- },
- {
- street_address: '1234 Schema Rd.',
- city: 'New York',
- state: 'Arizona',
- },
- ],
- };
-
- expect(toPathSchema(schema, '', schema, formData)).toStrictEqual({
- $name: '',
- address_list: {
- $name: 'address_list',
- 0: {
- $name: 'address_list.0',
- city: {
- $name: 'address_list.0.city',
- },
- state: {
- $name: 'address_list.0.state',
- },
- street_address: {
- $name: 'address_list.0.street_address',
- },
- },
- 1: {
- $name: 'address_list.1',
- city: {
- $name: 'address_list.1.city',
- },
- state: {
- $name: 'address_list.1.state',
- },
- street_address: {
- $name: 'address_list.1.street_address',
- },
- },
- },
+ expect(toIdSchema(schema, undefined, schema)).toStrictEqual({
+ $id: 'root',
+ foo: { $id: 'root_foo' },
+ bar: { $id: 'root_bar' },
});
});
- it('should return an pathSchema with different types of arrays', () => {
+ it('should handle idPrefix parameter', () => {
const schema = {
definitions: {
- Thing: {
+ testdef: {
type: 'object',
properties: {
- name: {
- type: 'string',
- default: 'Default name',
- },
+ foo: { type: 'string' },
+ bar: { type: 'string' },
},
},
},
+ $ref: '#/definitions/testdef',
+ };
+
+ expect(toIdSchema(schema, undefined, schema, {}, 'rjsf')).toStrictEqual({
+ $id: 'rjsf',
+ foo: { $id: 'rjsf_foo' },
+ bar: { $id: 'rjsf_bar' },
+ });
+ });
+
+ it('should handle null form data for object schemas', () => {
+ const schema = {
type: 'object',
properties: {
- listOfStrings: {
- type: 'array',
- title: 'A list of strings',
- items: {
- type: 'string',
- default: 'bazinga',
- },
- },
- multipleChoicesList: {
- type: 'array',
- title: 'A multiple choices list',
- items: {
- type: 'string',
- enum: ['foo', 'bar', 'fuzz', 'qux'],
- },
- uniqueItems: true,
- },
- fixedItemsList: {
- type: 'array',
- title: 'A list of fixed items',
- items: [
- {
- title: 'A string value',
- type: 'string',
- default: 'lorem ipsum',
- },
- {
- title: 'a boolean value',
- type: 'boolean',
- },
- ],
- additionalItems: {
- title: 'Additional item',
- type: 'number',
- },
- },
- minItemsList: {
- type: 'array',
- title: 'A list with a minimal number of items',
- minItems: 3,
- items: {
- $ref: '#/definitions/Thing',
- },
- },
- defaultsAndMinItems: {
- type: 'array',
- title: 'List and item level defaults',
- minItems: 5,
- default: ['carp', 'trout', 'bream'],
- items: {
- type: 'string',
- default: 'unidentified',
- },
- },
- nestedList: {
- type: 'array',
- title: 'Nested list',
- items: {
- type: 'array',
- title: 'Inner list',
- items: {
- type: 'string',
- default: 'lorem ipsum',
- },
- },
- },
- listOfObjects: {
- type: 'array',
- title: 'List of objects',
- items: {
- type: 'object',
- title: 'Object in list',
- properties: {
- name: {
- type: 'string',
- default: 'Default name',
- },
- id: {
- type: 'number',
- default: 'an id',
- },
- },
- },
- },
- unorderable: {
- title: 'Unorderable items',
- type: 'array',
- items: {
- type: 'string',
- default: 'lorem ipsum',
- },
- },
- unremovable: {
- title: 'Unremovable items',
- type: 'array',
- items: {
- type: 'string',
- default: 'lorem ipsum',
- },
- },
- noToolbar: {
- title: 'No add, remove and order buttons',
- type: 'array',
- items: {
- type: 'string',
- default: 'lorem ipsum',
- },
- },
- fixedNoToolbar: {
- title: 'Fixed array without buttons',
- type: 'array',
- items: [
- {
- title: 'A number',
- type: 'number',
- default: 42,
- },
- {
- title: 'A boolean',
- type: 'boolean',
- default: false,
- },
- ],
- additionalItems: {
- title: 'A string',
- type: 'string',
- default: 'lorem ipsum',
- },
- },
+ foo: { type: 'string' },
+ bar: { type: 'string' },
},
};
+ const formData = null;
+ const result = toIdSchema(schema, null, {}, formData, 'rjsf');
- const formData = {
- listOfStrings: ['foo', 'bar'],
- multipleChoicesList: ['foo', 'bar'],
- fixedItemsList: ['Some text', true, 123],
- minItemsList: [
- {
- name: 'Default name',
- },
- {
- name: 'Default name',
- },
- {
- name: 'Default name',
- },
- ],
- defaultsAndMinItems: ['carp', 'trout', 'bream', 'unidentified', 'unidentified'],
- nestedList: [['lorem', 'ipsum'], ['dolor']],
- listOfObjects: [{ name: 'name1', id: 123 }, { name: 'name2', id: 1234 }, { id: 12345 }],
- unorderable: ['one', 'two'],
- unremovable: ['one', 'two'],
- noToolbar: ['one', 'two'],
- fixedNoToolbar: [42, true, 'additional item one', 'additional item two'],
- };
+ expect(result).toStrictEqual({
+ $id: 'rjsf',
+ foo: { $id: 'rjsf_foo' },
+ bar: { $id: 'rjsf_bar' },
+ });
+ });
- expect(toPathSchema(schema, '', schema, formData)).toStrictEqual({
- $name: '',
- defaultsAndMinItems: {
- $name: 'defaultsAndMinItems',
- 0: {
- $name: 'defaultsAndMinItems.0',
- },
- 1: {
- $name: 'defaultsAndMinItems.1',
- },
- 2: {
- $name: 'defaultsAndMinItems.2',
- },
- 3: {
- $name: 'defaultsAndMinItems.3',
- },
- 4: {
- $name: 'defaultsAndMinItems.4',
- },
- },
- fixedItemsList: {
- $name: 'fixedItemsList',
- 0: {
- $name: 'fixedItemsList.0',
- },
- 1: {
- $name: 'fixedItemsList.1',
- },
- 2: {
- $name: 'fixedItemsList.2',
- },
- },
- fixedNoToolbar: {
- $name: 'fixedNoToolbar',
- 0: {
- $name: 'fixedNoToolbar.0',
- },
- 1: {
- $name: 'fixedNoToolbar.1',
- },
- 2: {
- $name: 'fixedNoToolbar.2',
- },
- 3: {
- $name: 'fixedNoToolbar.3',
- },
- },
- listOfObjects: {
- $name: 'listOfObjects',
- 0: {
- $name: 'listOfObjects.0',
- id: {
- $name: 'listOfObjects.0.id',
- },
- name: {
- $name: 'listOfObjects.0.name',
- },
- },
- 1: {
- $name: 'listOfObjects.1',
- id: {
- $name: 'listOfObjects.1.id',
- },
- name: {
- $name: 'listOfObjects.1.name',
- },
- },
- 2: {
- $name: 'listOfObjects.2',
- id: {
- $name: 'listOfObjects.2.id',
- },
- name: {
- $name: 'listOfObjects.2.name',
- },
- },
- },
- listOfStrings: {
- $name: 'listOfStrings',
- 0: {
- $name: 'listOfStrings.0',
- },
- 1: {
- $name: 'listOfStrings.1',
- },
- },
- minItemsList: {
- $name: 'minItemsList',
- 0: {
- $name: 'minItemsList.0',
- name: {
- $name: 'minItemsList.0.name',
- },
- },
- 1: {
- $name: 'minItemsList.1',
- name: {
- $name: 'minItemsList.1.name',
- },
- },
- 2: {
- $name: 'minItemsList.2',
- name: {
- $name: 'minItemsList.2.name',
- },
- },
- },
- multipleChoicesList: {
- $name: 'multipleChoicesList',
- 0: {
- $name: 'multipleChoicesList.0',
- },
- 1: {
- $name: 'multipleChoicesList.1',
- },
- },
- nestedList: {
- $name: 'nestedList',
- 0: {
- $name: 'nestedList.0',
- 0: {
- $name: 'nestedList.0.0',
- },
- 1: {
- $name: 'nestedList.0.1',
- },
- },
- 1: {
- $name: 'nestedList.1',
- 0: {
- $name: 'nestedList.1.0',
- },
- },
- },
- noToolbar: {
- $name: 'noToolbar',
- 0: {
- $name: 'noToolbar.0',
- },
- 1: {
- $name: 'noToolbar.1',
- },
- },
- unorderable: {
- $name: 'unorderable',
- 0: {
- $name: 'unorderable.0',
- },
- 1: {
- $name: 'unorderable.1',
- },
- },
- unremovable: {
- $name: 'unremovable',
- 0: {
- $name: 'unremovable.0',
- },
- 1: {
- $name: 'unremovable.1',
- },
+ it('should handle circular referencing', () => {
+ const treeSchema = {
+ properties: {},
+ };
+ treeSchema.properties.tree = treeSchema;
+ const rootSchema = {
+ definitions: {},
+ properties: {
+ tree: treeSchema,
},
+ type: 'object',
+ };
+
+ const result = toIdSchema(treeSchema, null, rootSchema);
+
+ expect(result).toStrictEqual({
+ $id: 'root',
});
});
});
@@ -3504,16 +1768,6 @@ describe('utils', () => {
const Widget = props =>
;
expect(getWidget(schema, Widget)({})).toStrictEqual( );
});
-
- it('should not fail on forwarded ref component', () => {
- const Widget = React.forwardRef((props, ref) =>
);
- expect(getWidget(schema, Widget)({})).toStrictEqual( );
- });
-
- it.skip('should not fail on memo component', () => {
- const Widget = React.memo(props =>
);
- expect(getWidget(schema, Widget)({})).toStrictEqual( );
- });
});
});
diff --git a/packages/oas-form/__tests__/validate_test.js b/packages/oas-form/__tests__/validate_test.js
deleted file mode 100644
index 97780daa4..000000000
--- a/packages/oas-form/__tests__/validate_test.js
+++ /dev/null
@@ -1,795 +0,0 @@
-/* eslint-disable global-require */
-import React from 'react';
-import { Simulate } from 'react-dom/test-utils';
-
-import validateFormData, { isValid, toErrorList } from '../src/validate';
-import { createFormComponent, submitForm } from './test_utils';
-
-describe('Validation', () => {
- describe('validate.isValid()', () => {
- it('should return true if the data is valid against the schema', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- },
- };
-
- expect(isValid(schema, { foo: 'bar' })).toBe(true);
- });
-
- it('should return false if the data is not valid against the schema', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- },
- };
-
- expect(isValid(schema, { foo: 12345 })).toBe(false);
- });
-
- it('should return false if the schema is invalid', () => {
- const schema = 'foobarbaz';
-
- expect(isValid(schema, { foo: 'bar' })).toBe(false);
- });
- });
-
- describe('validate.validateFormData()', () => {
- describe('No custom validate function', () => {
- const illFormedKey = 'bar.\'"[]()=+*&^%$#@!';
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- [illFormedKey]: { type: 'string' },
- },
- };
-
- let errors;
- let errorSchema;
-
- beforeEach(() => {
- const result = validateFormData({ foo: 42, [illFormedKey]: 41 }, schema);
- errors = result.errors;
- errorSchema = result.errorSchema;
- });
-
- it('should return an error list', () => {
- expect(errors).toHaveLength(2);
- expect(errors[0].message).toBe('should be string');
- expect(errors[1].message).toBe('should be string');
- });
-
- it('should return an errorSchema', () => {
- expect(errorSchema.foo.__errors).toHaveLength(1);
- expect(errorSchema.foo.__errors[0]).toBe('should be string');
- expect(errorSchema[illFormedKey].__errors).toHaveLength(1);
- expect(errorSchema[illFormedKey].__errors[0]).toBe('should be string');
- });
- });
-
- describe('Validating multipleOf with a float', () => {
- const schema = {
- type: 'object',
- properties: {
- price: {
- title: 'Price per task ($)',
- type: 'number',
- multipleOf: 0.01,
- minimum: 0,
- },
- },
- };
-
- let errors;
-
- beforeEach(() => {
- const result = validateFormData({ price: 0.14 }, schema);
- errors = result.errors;
- });
-
- it('should not return an error', () => {
- expect(errors).toHaveLength(0);
- });
- });
-
- describe('validating using custom meta schema', () => {
- const schema = {
- $ref: '#/definitions/Dataset',
- $schema: 'http://json-schema.org/draft-04/schema#',
- definitions: {
- Dataset: {
- properties: {
- datasetId: {
- pattern: '\\d+',
- type: 'string',
- },
- },
- required: ['datasetId'],
- type: 'object',
- },
- },
- };
- const metaSchemaDraft4 = require('ajv/lib/refs/json-schema-draft-04.json');
- const metaSchemaDraft6 = require('ajv/lib/refs/json-schema-draft-06.json');
-
- it('should return a validation error about meta schema when meta schema is not defined', () => {
- const errors = validateFormData({ datasetId: 'some kind of text' }, schema);
- const errMessage = 'no schema with key or ref "http://json-schema.org/draft-04/schema#"';
- expect(errors.errors[0].stack).toBe(errMessage);
- expect(errors.errors).toStrictEqual([
- {
- stack: errMessage,
- },
- ]);
- expect(errors.errorSchema).toStrictEqual({
- $schema: { __errors: [errMessage] },
- });
- });
-
- it('should return a validation error about formData', () => {
- const errors = validateFormData({ datasetId: 'some kind of text' }, schema, null, null, [metaSchemaDraft4]);
- expect(errors.errors).toHaveLength(1);
- expect(errors.errors[0].stack).toBe('.datasetId should match pattern "\\d+"');
- });
-
- it('should return a validation error about formData, when used with multiple meta schemas', () => {
- const errors = validateFormData({ datasetId: 'some kind of text' }, schema, null, null, [
- metaSchemaDraft4,
- metaSchemaDraft6,
- ]);
- expect(errors.errors).toHaveLength(1);
- expect(errors.errors[0].stack).toBe('.datasetId should match pattern "\\d+"');
- });
- });
-
- describe('validating using custom string formats', () => {
- const schema = {
- type: 'object',
- properties: {
- phone: {
- type: 'string',
- format: 'phone-us',
- },
- },
- };
-
- it('should not return a validation error if unknown string format is used', () => {
- const result = validateFormData({ phone: '800.555.2368' }, schema);
- expect(result.errors).toHaveLength(0);
- });
-
- it('should return a validation error about formData', () => {
- const result = validateFormData({ phone: '800.555.2368' }, schema, null, null, null, {
- 'phone-us': /\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}$/,
- });
-
- expect(result.errors).toHaveLength(1);
- expect(result.errors[0].stack).toBe('.phone should match format "phone-us"');
- });
-
- it('prop updates with new custom formats are accepted', () => {
- const result = validateFormData(
- { phone: 'abc' },
- {
- type: 'object',
- properties: {
- phone: {
- type: 'string',
- format: 'area-code',
- },
- },
- },
- null,
- null,
- null,
- { 'area-code': /\d{3}/ }
- );
-
- expect(result.errors).toHaveLength(1);
- expect(result.errors[0].stack).toBe('.phone should match format "area-code"');
- });
- });
-
- describe('Custom validate function', () => {
- let errors;
- let errorSchema;
-
- const schema = {
- type: 'object',
- required: ['pass1', 'pass2'],
- properties: {
- pass1: { type: 'string' },
- pass2: { type: 'string' },
- },
- };
-
- beforeEach(() => {
- const validate = (formData, errors) => {
- if (formData.pass1 !== formData.pass2) {
- errors.pass2.addError("passwords don't match.");
- }
- return errors;
- };
- const formData = { pass1: 'a', pass2: 'b' };
- const result = validateFormData(formData, schema, validate);
- errors = result.errors;
- errorSchema = result.errorSchema;
- });
-
- it('should return an error list', () => {
- expect(errors).toHaveLength(1);
- expect(errors[0].stack).toBe("pass2: passwords don't match.");
- });
-
- it('should return an errorSchema', () => {
- expect(errorSchema.pass2.__errors).toHaveLength(1);
- expect(errorSchema.pass2.__errors[0]).toBe("passwords don't match.");
- });
- });
-
- describe('Data-Url validation', () => {
- const schema = {
- type: 'object',
- properties: {
- dataUrlWithName: { type: 'string', format: 'data-url' },
- dataUrlWithoutName: { type: 'string', format: 'data-url' },
- },
- };
-
- it('Data-Url with name is accepted', () => {
- const formData = {
- dataUrlWithName: 'data:text/plain;name=file1.txt;base64,x=',
- };
- const result = validateFormData(formData, schema);
- expect(result.errors).toHaveLength(0);
- });
-
- it('Data-Url without name is accepted', () => {
- const formData = {
- dataUrlWithoutName: 'data:text/plain;base64,x=',
- };
- const result = validateFormData(formData, schema);
- expect(result.errors).toHaveLength(0);
- });
- });
-
- describe('Invalid schema', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: {
- type: 'string',
- required: 'invalid_type_non_array',
- },
- },
- };
-
- let errors;
- let errorSchema;
-
- beforeEach(() => {
- const result = validateFormData({ foo: 42 }, schema);
- errors = result.errors;
- errorSchema = result.errorSchema;
- });
-
- it('should return an error list', () => {
- expect(errors).toHaveLength(1);
- expect(errors[0].name).toBe('type');
- expect(errors[0].property).toBe(".properties['foo'].required");
- expect(errors[0].schemaPath).toBe('#/definitions/stringArray/type'); // TODO: This schema path is wrong due to a bug in ajv; change this test when https://github.com/epoberezkin/ajv/issues/512 is fixed.
- expect(errors[0].message).toBe('should be array');
- });
-
- it('should return an errorSchema', () => {
- expect(errorSchema.properties.foo.required.__errors).toHaveLength(1);
- expect(errorSchema.properties.foo.required.__errors[0]).toBe('should be array');
- });
- });
- });
-
- describe('toErrorList()', () => {
- it('should convert an errorSchema into a flat list', () => {
- expect(
- toErrorList({
- __errors: ['err1', 'err2'],
- a: {
- b: {
- __errors: ['err3', 'err4'],
- },
- },
- c: {
- __errors: ['err5'],
- },
- })
- ).toStrictEqual([
- { stack: 'root: err1' },
- { stack: 'root: err2' },
- { stack: 'b: err3' },
- { stack: 'b: err4' },
- { stack: 'c: err5' },
- ]);
- });
- });
-
- describe('transformErrors', () => {
- const illFormedKey = 'bar.\'"[]()=+*&^%$#@!';
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- [illFormedKey]: { type: 'string' },
- },
- };
- const newErrorMessage = 'Better error message';
- const transformErrors = errors => {
- return [{ ...errors[0], message: newErrorMessage }];
- };
-
- let errors;
-
- beforeEach(() => {
- const result = validateFormData({ foo: 42, [illFormedKey]: 41 }, schema, undefined, transformErrors);
- errors = result.errors;
- });
-
- it('should use transformErrors function', () => {
- expect(errors).not.toHaveLength(0);
- expect(errors[0].message).toBe(newErrorMessage);
- });
- });
-
- describe('Form integration', () => {
- describe('JSONSchema validation', () => {
- describe('Required fields', () => {
- const schema = {
- type: 'object',
- required: ['foo'],
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
- },
- };
-
- let onError;
- let node;
-
- beforeEach(() => {
- const compInfo = createFormComponent({
- schema,
- formData: {
- foo: undefined,
- },
- });
- onError = compInfo.onError;
- node = compInfo.node;
- submitForm(node);
- });
-
- it('should trigger onError call', () => {
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'is a required property',
- name: 'required',
- params: { missingProperty: 'foo' },
- property: '.foo',
- schemaPath: '#/required',
- stack: '.foo is a required property',
- },
- ])
- );
- });
-
- it('should render errors', () => {
- expect(node.querySelectorAll('.errors li')).toHaveLength(1);
- expect(node.querySelector('.errors li')).toHaveTextContent('.foo is a required property');
- });
- });
-
- describe('Min length', () => {
- const schema = {
- type: 'object',
- required: ['foo'],
- properties: {
- foo: {
- type: 'string',
- minLength: 10,
- },
- },
- };
-
- let node;
- let onError;
-
- beforeEach(() => {
- onError = jest.fn();
- const compInfo = createFormComponent({
- schema,
- formData: {
- foo: '123456789',
- },
- onError,
- });
- node = compInfo.node;
-
- submitForm(node);
- });
-
- it('should render errors', () => {
- expect(node.querySelectorAll('.errors li')).toHaveLength(1);
- expect(node.querySelector('.errors li')).toHaveTextContent('.foo should NOT be shorter than 10 characters');
- });
-
- it('should trigger the onError handler', () => {
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should NOT be shorter than 10 characters',
- name: 'minLength',
- params: { limit: 10 },
- property: '.foo',
- schemaPath: '#/properties/foo/minLength',
- stack: '.foo should NOT be shorter than 10 characters',
- },
- ])
- );
- });
- });
- });
-
- describe('Custom Form validation', () => {
- it('should validate a simple string value', () => {
- const schema = { type: 'string' };
- const formData = 'a';
-
- function validate(formData, errors) {
- if (formData !== 'hello') {
- errors.addError('Invalid');
- }
- return errors;
- }
-
- const { onError, node } = createFormComponent({
- schema,
- validate,
- formData,
- });
-
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(expect.arrayContaining([{ stack: 'root: Invalid' }]));
- });
-
- it('should live validate a simple string value when liveValidate is set to true', () => {
- const schema = { type: 'string' };
- const formData = 'a';
-
- function validate(formData, errors) {
- if (formData !== 'hello') {
- errors.addError('Invalid');
- }
- return errors;
- }
-
- const { onChange, node } = createFormComponent({
- schema,
- validate,
- formData,
- liveValidate: true,
- });
- Simulate.change(node.querySelector('input'), {
- target: { value: '1234' },
- });
-
- expect(onChange).toHaveBeenLastCalledWith(
- expect.objectContaining({
- errorSchema: { __errors: ['Invalid'] },
- errors: [{ stack: 'root: Invalid' }],
- formData: '1234',
- })
- );
- });
-
- it('should submit form on valid data', () => {
- const schema = { type: 'string' };
- const formData = 'hello';
- const onSubmit = jest.fn();
-
- function validate(formData, errors) {
- if (formData !== 'hello') {
- errors.addError('Invalid');
- }
- return errors;
- }
-
- const { node } = createFormComponent({
- schema,
- formData,
- validate,
- onSubmit,
- });
-
- submitForm(node);
-
- expect(onSubmit).toHaveBeenCalled();
- });
-
- it('should prevent form submission on invalid data', () => {
- const schema = { type: 'string' };
- const formData = 'a';
- const onSubmit = jest.fn();
- const onError = jest.fn();
-
- function validate(formData, errors) {
- if (formData !== 'hello') {
- errors.addError('Invalid');
- }
- return errors;
- }
-
- const { node } = createFormComponent({
- schema,
- formData,
- validate,
- onSubmit,
- onError,
- });
-
- submitForm(node);
-
- expect(onSubmit).not.toHaveBeenCalled();
- expect(onError).toHaveBeenCalled();
- });
-
- it('should validate a simple object', () => {
- const schema = {
- type: 'object',
- properties: {
- pass1: { type: 'string', minLength: 3 },
- pass2: { type: 'string', minLength: 3 },
- },
- };
-
- const formData = { pass1: 'aaa', pass2: 'b' };
-
- function validate(formData, errors) {
- const { pass1, pass2 } = formData;
- if (pass1 !== pass2) {
- errors.pass2.addError("Passwords don't match");
- }
- return errors;
- }
-
- const { node, onError } = createFormComponent({
- schema,
- validate,
- formData,
- });
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- { stack: 'pass2: should NOT be shorter than 3 characters' },
- { stack: "pass2: Passwords don't match" },
- ])
- );
- });
-
- it('should validate an array of object', () => {
- const schema = {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- pass1: { type: 'string' },
- pass2: { type: 'string' },
- },
- },
- };
-
- const formData = [
- { pass1: 'a', pass2: 'b' },
- { pass1: 'a', pass2: 'a' },
- ];
-
- function validate(formData, errors) {
- formData.forEach(({ pass1, pass2 }, i) => {
- if (pass1 !== pass2) {
- errors[i].pass2.addError("Passwords don't match");
- }
- });
- return errors;
- }
-
- const { node, onError } = createFormComponent({
- schema,
- validate,
- formData,
- });
-
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(expect.arrayContaining([{ stack: "pass2: Passwords don't match" }]));
- });
-
- it('should validate a simple array', () => {
- const schema = {
- type: 'array',
- items: {
- type: 'string',
- },
- };
-
- const formData = ['aaa', 'bbb', 'ccc'];
-
- function validate(formData, errors) {
- if (formData.indexOf('bbb') !== -1) {
- errors.addError('Forbidden value: bbb');
- }
- return errors;
- }
-
- const { node, onError } = createFormComponent({
- schema,
- validate,
- formData,
- });
- submitForm(node);
- expect(onError).toHaveBeenLastCalledWith(expect.arrayContaining([{ stack: 'root: Forbidden value: bbb' }]));
- });
- });
-
- describe('showErrorList prop validation', () => {
- describe('Required fields', () => {
- const schema = {
- type: 'object',
- required: ['foo'],
- properties: {
- foo: { type: 'string' },
- bar: { type: 'string' },
- },
- };
-
- let node;
- let onError;
-
- beforeEach(() => {
- const compInfo = createFormComponent({
- schema,
- formData: {
- foo: undefined,
- },
- showErrorList: false,
- });
- node = compInfo.node;
- onError = compInfo.onError;
-
- submitForm(node);
- });
-
- it('should not render error list if showErrorList prop true', () => {
- expect(node.querySelectorAll('.errors li')).toHaveLength(0);
- });
-
- it('should trigger onError call', () => {
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'is a required property',
- name: 'required',
- params: { missingProperty: 'foo' },
- property: '.foo',
- schemaPath: '#/required',
- stack: '.foo is a required property',
- },
- ])
- );
- });
- });
- });
-
- describe('Custom ErrorList', () => {
- const schema = {
- type: 'string',
- minLength: 1,
- };
-
- const uiSchema = {
- foo: 'bar',
- };
-
- const formData = 0;
-
- const CustomErrorList = ({ errors, errorSchema, schema, uiSchema, formContext: { className } }) => (
-
-
{errors.length} custom
-
{errorSchema.__errors[0]}
-
{schema.type}
-
{uiSchema.foo}
-
-
- );
-
- it('should use CustomErrorList', () => {
- const { node } = createFormComponent({
- schema,
- uiSchema,
- liveValidate: true,
- formData,
- ErrorList: CustomErrorList,
- formContext: { className: 'foo' },
- });
- expect(node.querySelectorAll('.CustomErrorList')).toHaveLength(1);
- expect(node.querySelector('.CustomErrorList')).toHaveTextContent('1 custom');
- expect(node.querySelectorAll('.ErrorSchema')).toHaveLength(1);
- expect(node.querySelector('.ErrorSchema')).toHaveTextContent('should be string');
- expect(node.querySelectorAll('.Schema')).toHaveLength(1);
- expect(node.querySelector('.Schema')).toHaveTextContent('string');
- expect(node.querySelectorAll('.UiSchema')).toHaveLength(1);
- expect(node.querySelector('.UiSchema')).toHaveTextContent('bar');
- expect(node.querySelectorAll('.foo')).toHaveLength(1);
- });
- });
-
- describe('Custom meta schema', () => {
- let onError;
- let node;
- const formData = {
- datasetId: 'no err',
- };
-
- const schema = {
- $ref: '#/definitions/Dataset',
- $schema: 'http://json-schema.org/draft-04/schema#',
- definitions: {
- Dataset: {
- properties: {
- datasetId: {
- pattern: '\\d+',
- type: 'string',
- },
- },
- required: ['datasetId'],
- type: 'object',
- },
- },
- };
-
- beforeEach(() => {
- const withMetaSchema = createFormComponent({
- schema,
- formData,
- liveValidate: true,
- additionalMetaSchemas: [require('ajv/lib/refs/json-schema-draft-04.json')],
- });
- node = withMetaSchema.node;
- onError = withMetaSchema.onError;
- submitForm(node);
- });
-
- it('should be used to validate schema', () => {
- expect(node.querySelectorAll('.errors li')).toHaveLength(1);
- expect(onError).toHaveBeenLastCalledWith(
- expect.arrayContaining([
- {
- message: 'should match pattern "\\d+"',
- name: 'pattern',
- params: { pattern: '\\d+' },
- property: '.datasetId',
- schemaPath: '#/properties/datasetId/pattern',
- stack: '.datasetId should match pattern "\\d+"',
- },
- ])
- );
- onError.mockClear();
-
- Simulate.change(node.querySelector('input'), {
- target: { value: '1234' },
- });
- expect(node.querySelectorAll('.errors li')).toHaveLength(0);
- expect(onError).not.toHaveBeenCalled();
- });
- });
- });
-});
diff --git a/packages/oas-form/__tests__/withTheme_test.js b/packages/oas-form/__tests__/withTheme_test.js
deleted file mode 100644
index 0d67e4c2f..000000000
--- a/packages/oas-form/__tests__/withTheme_test.js
+++ /dev/null
@@ -1,242 +0,0 @@
-import React, { Component, createRef } from 'react';
-
-import { withTheme } from '../src';
-import { createComponent } from './test_utils';
-
-const WrapperClassComponent = (...args) => {
- return class extends Component {
- render() {
- const Cmp = withTheme(...args);
- return ;
- }
- };
-};
-
-describe('withTheme', () => {
- describe('With fields', () => {
- it('should use the withTheme field', () => {
- const fields = {
- StringField() {
- return
;
- },
- };
- const schema = {
- type: 'object',
- properties: {
- fieldA: {
- type: 'string',
- },
- fieldB: {
- type: 'string',
- },
- },
- };
- const uiSchema = {};
- const { node } = createComponent(WrapperClassComponent({ fields }), {
- schema,
- uiSchema,
- });
- expect(node.querySelectorAll('.string-field')).toHaveLength(2);
- });
-
- it('should use withTheme field and the user defined field', () => {
- const themeFields = {
- StringField() {
- return
;
- },
- };
- const userFields = {
- NumberField() {
- return
;
- },
- };
- const schema = {
- type: 'object',
- properties: {
- fieldA: {
- type: 'string',
- },
- fieldB: {
- type: 'number',
- },
- },
- };
- const uiSchema = {};
- const { node } = createComponent(WrapperClassComponent({ fields: themeFields }), {
- schema,
- uiSchema,
- fields: userFields,
- });
- expect(node.querySelectorAll('.string-field')).toHaveLength(1);
- expect(node.querySelectorAll('.number-field')).toHaveLength(1);
- });
-
- it('should use only the user defined field', () => {
- const themeFields = {
- StringField() {
- return
;
- },
- };
- const userFields = {
- StringField() {
- return
;
- },
- };
- const schema = {
- type: 'object',
- properties: {
- fieldA: {
- type: 'string',
- },
- fieldB: {
- type: 'string',
- },
- },
- };
- const uiSchema = {};
- const { node } = createComponent(WrapperClassComponent({ fields: themeFields }), {
- schema,
- uiSchema,
- fields: userFields,
- });
- expect(node.querySelectorAll('.string-field')).toHaveLength(0);
- expect(node.querySelectorAll('.form-control')).toHaveLength(2);
- });
- });
-
- describe('With widgets', () => {
- it('should use the withTheme widget', () => {
- const widgets = {
- TextWidget: () =>
,
- };
- const schema = {
- type: 'string',
- };
- const uiSchema = {};
- const { node } = createComponent(WrapperClassComponent({ widgets }), {
- schema,
- uiSchema,
- });
- expect(node.querySelectorAll('#test')).toHaveLength(1);
- });
-
- it('should use the withTheme widget as well as user defined widget', () => {
- const themeWidgets = {
- TextWidget: () =>
,
- };
- const userWidgets = {
- DateWidget: () =>
,
- };
- const schema = {
- type: 'object',
- properties: {
- fieldA: {
- type: 'string',
- },
- fieldB: {
- format: 'date',
- type: 'string',
- },
- },
- };
- const uiSchema = {};
- const { node } = createComponent(WrapperClassComponent({ widgets: themeWidgets }), {
- schema,
- uiSchema,
- widgets: userWidgets,
- });
- expect(node.querySelectorAll('#test-theme-widget')).toHaveLength(1);
- expect(node.querySelectorAll('#test-user-widget')).toHaveLength(1);
- });
-
- it('should use only the user defined widget', () => {
- const themeWidgets = {
- TextWidget: () =>
,
- };
- const userWidgets = {
- TextWidget: () =>
,
- };
- const schema = {
- type: 'object',
- properties: {
- fieldA: {
- type: 'string',
- },
- },
- };
- const uiSchema = {};
- const { node } = createComponent(WrapperClassComponent({ widgets: themeWidgets }), {
- schema,
- uiSchema,
- widgets: userWidgets,
- });
- expect(node.querySelectorAll('#test-theme-widget')).toHaveLength(0);
- expect(node.querySelectorAll('#test-user-widget')).toHaveLength(1);
- });
- });
-
- describe('With templates', () => {
- it('should use the withTheme template', () => {
- const themeTemplates = {
- FieldTemplate() {
- return
;
- },
- };
- const schema = {
- type: 'object',
- properties: {
- fieldA: {
- type: 'string',
- },
- fieldB: {
- type: 'string',
- },
- },
- };
- const uiSchema = {};
- const { node } = createComponent(WrapperClassComponent({ ...themeTemplates }), {
- schema,
- uiSchema,
- });
- expect(node.querySelectorAll('.with-theme-field-template')).toHaveLength(1);
- });
-
- it('should use only the user defined template', () => {
- const themeTemplates = {
- FieldTemplate() {
- return
;
- },
- };
- const userTemplates = {
- FieldTemplate() {
- return
;
- },
- };
-
- const schema = {
- type: 'object',
- properties: { foo: { type: 'string' }, bar: { type: 'string' } },
- };
- const { node } = createComponent(WrapperClassComponent({ ...themeTemplates }), {
- schema,
- ...userTemplates,
- });
- expect(node.querySelectorAll('.with-theme-field-template')).toHaveLength(0);
- expect(node.querySelectorAll('.user-field-template')).toHaveLength(1);
- });
-
- it('should forward the ref', () => {
- const ref = createRef();
- const schema = {};
- const uiSchema = {};
-
- createComponent(withTheme({}), {
- schema,
- uiSchema,
- ref,
- });
-
- expect(ref.current.submit).not.toBeUndefined();
- });
- });
-});
diff --git a/packages/oas-form/package-lock.json b/packages/oas-form/package-lock.json
index 124cebddc..737a97bfc 100644
--- a/packages/oas-form/package-lock.json
+++ b/packages/oas-form/package-lock.json
@@ -352,48 +352,6 @@
}
}
},
- "@babel/helper-create-class-features-plugin": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.4.4.tgz",
- "integrity": "sha512-UbBHIa2qeAGgyiNR9RszVF7bUHEdgS4JAUNT8SiqrAN6YJVxlOxeLr5pBzb5kan302dejJ9nla4RyKcR1XT6XA==",
- "dev": true,
- "requires": {
- "@babel/helper-function-name": "^7.1.0",
- "@babel/helper-member-expression-to-functions": "^7.0.0",
- "@babel/helper-optimise-call-expression": "^7.0.0",
- "@babel/helper-plugin-utils": "^7.0.0",
- "@babel/helper-replace-supers": "^7.4.4",
- "@babel/helper-split-export-declaration": "^7.4.4"
- },
- "dependencies": {
- "@babel/helper-split-export-declaration": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz",
- "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.4.4"
- }
- },
- "@babel/types": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz",
- "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==",
- "dev": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- },
- "lodash": {
- "version": "4.17.11",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
- "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
- "dev": true
- }
- }
- },
"@babel/helper-create-regexp-features-plugin": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz",
@@ -566,26 +524,6 @@
}
}
},
- "@babel/helper-function-name": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz",
- "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==",
- "dev": true,
- "requires": {
- "@babel/helper-get-function-arity": "^7.0.0",
- "@babel/template": "^7.1.0",
- "@babel/types": "^7.0.0"
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz",
- "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.0.0"
- }
- },
"@babel/helper-hoist-variables": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz",
@@ -620,15 +558,6 @@
}
}
},
- "@babel/helper-member-expression-to-functions": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz",
- "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.0.0"
- }
- },
"@babel/helper-module-imports": {
"version": "7.12.5",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz",
@@ -801,15 +730,6 @@
}
}
},
- "@babel/helper-optimise-call-expression": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz",
- "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.0.0"
- }
- },
"@babel/helper-plugin-utils": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz",
@@ -852,103 +772,6 @@
}
}
},
- "@babel/helper-replace-supers": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz",
- "integrity": "sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==",
- "dev": true,
- "requires": {
- "@babel/helper-member-expression-to-functions": "^7.0.0",
- "@babel/helper-optimise-call-expression": "^7.0.0",
- "@babel/traverse": "^7.4.4",
- "@babel/types": "^7.4.4"
- },
- "dependencies": {
- "@babel/generator": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz",
- "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.4.4",
- "jsesc": "^2.5.1",
- "lodash": "^4.17.11",
- "source-map": "^0.5.0",
- "trim-right": "^1.0.1"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz",
- "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.4.4"
- }
- },
- "@babel/parser": {
- "version": "7.4.5",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz",
- "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==",
- "dev": true
- },
- "@babel/traverse": {
- "version": "7.4.5",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz",
- "integrity": "sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/generator": "^7.4.4",
- "@babel/helper-function-name": "^7.1.0",
- "@babel/helper-split-export-declaration": "^7.4.4",
- "@babel/parser": "^7.4.5",
- "@babel/types": "^7.4.4",
- "debug": "^4.1.0",
- "globals": "^11.1.0",
- "lodash": "^4.17.11"
- }
- },
- "@babel/types": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz",
- "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==",
- "dev": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- },
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- },
- "jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
- "dev": true
- },
- "lodash": {
- "version": "4.17.15",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
- "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
- "dev": true
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- }
- }
- },
"@babel/helper-simple-access": {
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz",
@@ -1367,16 +1190,6 @@
}
}
},
- "@babel/plugin-proposal-class-properties": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.4.4.tgz",
- "integrity": "sha512-WjKTI8g8d5w1Bc9zgwSz2nfrsNQsXcCf9J9cdCvrJV6RF56yztwm4TmJC0MgJ9tvwO9gUA/mcYe89bLdGfiXFg==",
- "dev": true,
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.4.4",
- "@babel/helper-plugin-utils": "^7.0.0"
- }
- },
"@babel/plugin-proposal-dynamic-import": {
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz",
@@ -2944,6 +2757,112 @@
}
}
},
+ "@babel/plugin-transform-react-display-name": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.13.tgz",
+ "integrity": "sha512-MprESJzI9O5VnJZrL7gg1MpdqmiFcUv41Jc7SahxYsNP2kDkFqClxxTZq+1Qv4AFCamm+GXMRDQINNn+qrxmiA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.12.13"
+ },
+ "dependencies": {
+ "@babel/helper-plugin-utils": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz",
+ "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==",
+ "dev": true
+ }
+ }
+ },
+ "@babel/plugin-transform-react-jsx": {
+ "version": "7.12.16",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.16.tgz",
+ "integrity": "sha512-dNu0vAbIk8OkqJfGtYF6ADk6jagoyAl+Ks5aoltbAlfoKv8d6yooi3j+kObeSQaCj9PgN6KMZPB90wWyek5TmQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.12.13",
+ "@babel/helper-module-imports": "^7.12.13",
+ "@babel/helper-plugin-utils": "^7.12.13",
+ "@babel/plugin-syntax-jsx": "^7.12.13",
+ "@babel/types": "^7.12.13"
+ },
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz",
+ "integrity": "sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.13"
+ }
+ },
+ "@babel/helper-module-imports": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz",
+ "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.13"
+ }
+ },
+ "@babel/helper-plugin-utils": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz",
+ "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==",
+ "dev": true
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
+ "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==",
+ "dev": true
+ },
+ "@babel/types": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz",
+ "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.12.11",
+ "lodash": "^4.17.19",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "dev": true
+ }
+ }
+ },
+ "@babel/plugin-transform-react-jsx-development": {
+ "version": "7.12.16",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.16.tgz",
+ "integrity": "sha512-GOp5SkMC4zhHwLbOSYhF+WpIZSf5bGzaKQTT9jWkemJRDM/CE6FtPydXjEYO3pHcna2Zjvg4mQ1lfjOR/4jsaQ==",
+ "dev": true,
+ "requires": {
+ "@babel/plugin-transform-react-jsx": "^7.12.16"
+ }
+ },
+ "@babel/plugin-transform-react-pure-annotations": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz",
+ "integrity": "sha512-RqeaHiwZtphSIUZ5I85PEH19LOSzxfuEazoY7/pWASCAIBuATQzpSVD+eT6MebeeZT2F4eSL0u4vw6n4Nm0Mjg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.10.4",
+ "@babel/helper-plugin-utils": "^7.10.4"
+ },
+ "dependencies": {
+ "@babel/helper-plugin-utils": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz",
+ "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==",
+ "dev": true
+ }
+ }
+ },
"@babel/plugin-transform-regenerator": {
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz",
@@ -3433,6 +3352,27 @@
}
}
},
+ "@babel/preset-react": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.13.tgz",
+ "integrity": "sha512-TYM0V9z6Abb6dj1K7i5NrEhA13oS5ujUYQYDfqIBXYHOc2c2VkFgc+q9kyssIyUfy4/hEwqrgSlJ/Qgv8zJLsA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.12.13",
+ "@babel/plugin-transform-react-display-name": "^7.12.13",
+ "@babel/plugin-transform-react-jsx": "^7.12.13",
+ "@babel/plugin-transform-react-jsx-development": "^7.12.12",
+ "@babel/plugin-transform-react-pure-annotations": "^7.12.1"
+ },
+ "dependencies": {
+ "@babel/helper-plugin-utils": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz",
+ "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==",
+ "dev": true
+ }
+ }
+ },
"@babel/runtime": {
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz",
@@ -3442,15 +3382,14 @@
"regenerator-runtime": "^0.13.4"
}
},
- "@babel/template": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz",
- "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==",
+ "@babel/runtime-corejs3": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.12.13.tgz",
+ "integrity": "sha512-8fSpqYRETHATtNitsCXq8QQbKJP31/KnDl2Wz2Vtui9nKzjss2ysuZtyVsWjBtvkeEFo346gkwjYPab1hvrXkQ==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/parser": "^7.2.2",
- "@babel/types": "^7.2.2"
+ "core-js-pure": "^3.0.0",
+ "regenerator-runtime": "^0.13.4"
}
},
"@babel/traverse": {
@@ -4321,19 +4260,10 @@
}
}
},
- "@sinonjs/commons": {
- "version": "1.8.2",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz",
- "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==",
- "dev": true,
- "requires": {
- "type-detect": "4.0.8"
- }
- },
- "@sinonjs/fake-timers": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz",
- "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==",
+ "@nodelib/fs.scandir": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
+ "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.7.0"
@@ -4452,6 +4382,110 @@
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==",
"dev": true
},
+ "@typescript-eslint/experimental-utils": {
+ "version": "4.15.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.1.tgz",
+ "integrity": "sha512-9LQRmOzBRI1iOdJorr4jEnQhadxK4c9R2aEAsm7WE/7dq8wkKD1suaV0S/JucTL8QlYUPU1y2yjqg+aGC0IQBQ==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.3",
+ "@typescript-eslint/scope-manager": "4.15.1",
+ "@typescript-eslint/types": "4.15.1",
+ "@typescript-eslint/typescript-estree": "4.15.1",
+ "eslint-scope": "^5.0.0",
+ "eslint-utils": "^2.0.0"
+ }
+ },
+ "@typescript-eslint/scope-manager": {
+ "version": "4.15.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.1.tgz",
+ "integrity": "sha512-ibQrTFcAm7yG4C1iwpIYK7vDnFg+fKaZVfvyOm3sNsGAerKfwPVFtYft5EbjzByDJ4dj1WD8/34REJfw/9wdVA==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "4.15.1",
+ "@typescript-eslint/visitor-keys": "4.15.1"
+ }
+ },
+ "@typescript-eslint/types": {
+ "version": "4.15.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.15.1.tgz",
+ "integrity": "sha512-iGsaUyWFyLz0mHfXhX4zO6P7O3sExQpBJ2dgXB0G5g/8PRVfBBsmQIc3r83ranEQTALLR3Vko/fnCIVqmH+mPw==",
+ "dev": true
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "4.15.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.1.tgz",
+ "integrity": "sha512-z8MN3CicTEumrWAEB2e2CcoZa3KP9+SMYLIA2aM49XW3cWIaiVSOAGq30ffR5XHxRirqE90fgLw3e6WmNx5uNw==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "4.15.1",
+ "@typescript-eslint/visitor-keys": "4.15.1",
+ "debug": "^4.1.1",
+ "globby": "^11.0.1",
+ "is-glob": "^4.0.1",
+ "semver": "^7.3.2",
+ "tsutils": "^3.17.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "semver": {
+ "version": "7.3.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
+ "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ }
+ }
+ },
+ "@typescript-eslint/visitor-keys": {
+ "version": "4.15.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.1.tgz",
+ "integrity": "sha512-tYzaTP9plooRJY8eNlpAewTOqtWW/4ff/5wBjNVaJ0S0wC4Gpq/zDVRTJa5bq2v1pCNQ08xxMCndcvR+h7lMww==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "4.15.1",
+ "eslint-visitor-keys": "^2.0.0"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
+ "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
+ "dev": true
+ }
+ }
+ },
"@webassemblyjs/ast": {
"version": "1.7.8",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.8.tgz",
@@ -4687,6 +4721,24 @@
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
"dev": true
},
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ajv-keywords": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+ "dev": true
+ },
"alphanum-sort": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
@@ -4870,6 +4922,18 @@
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
"dev": true
},
+ "axe-core": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.2.tgz",
+ "integrity": "sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg==",
+ "dev": true
+ },
+ "axobject-query": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
+ "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==",
+ "dev": true
+ },
"babel-eslint": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz",
@@ -7337,6 +7401,12 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
+ "fast-diff": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
+ "dev": true
+ },
"fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
@@ -12272,6 +12342,12 @@
"integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
"dev": true
},
+ "queue-microtask": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz",
+ "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==",
+ "dev": true
+ },
"randombytes": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz",
@@ -12689,6 +12765,15 @@
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
"dev": true
},
+ "run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "requires": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
"run-queue": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
@@ -13772,11 +13857,40 @@
}
}
},
- "trim-right": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
- "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
- "dev": true
+ "tsconfig-paths": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
+ "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==",
+ "dev": true,
+ "requires": {
+ "@types/json5": "^0.0.29",
+ "json5": "^1.0.1",
+ "minimist": "^1.2.0",
+ "strip-bom": "^3.0.0"
+ },
+ "dependencies": {
+ "json5": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "dev": true
+ }
+ }
},
"tslib": {
"version": "1.9.3",
@@ -13841,6 +13955,12 @@
"is-typedarray": "^1.0.0"
}
},
+ "ua-parser-js": {
+ "version": "0.7.24",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.24.tgz",
+ "integrity": "sha512-yo+miGzQx5gakzVK3QFfN0/L9uVhosXBBO7qmnk7c2iw1IhL212wfA3zbnI54B0obGwC/5NWub/iT9sReMx+Fw==",
+ "dev": true
+ },
"uglify-es": {
"version": "3.3.9",
"resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
diff --git a/packages/oas-form/package.json b/packages/oas-form/package.json
index a734abdb4..18a686a0c 100644
--- a/packages/oas-form/package.json
+++ b/packages/oas-form/package.json
@@ -18,9 +18,7 @@
"test": "__tests__"
},
"scripts": {
- "build": "npm run dist",
- "build:lib": "rimraf lib && NODE_ENV=production babel -d lib/ src/",
- "build:dist": "rimraf dist && NODE_ENV=production webpack --config webpack.config.dist.js",
+ "build": "NODE_ENV=production webpack",
"dist": "npm run build:lib && npm run build:dist",
"lint": "eslint . --ext js --ext jsx",
"prettier": "prettier --list-different --write \"./**/**.{js,jsx}\"",
@@ -30,12 +28,8 @@
"test": "jest --coverage"
},
"dependencies": {
- "@babel/runtime-corejs2": "^7.4.5",
- "ajv": "^6.7.0",
- "core-js": "^2.5.7",
"json-schema-merge-allof": "^0.6.0",
"jsonpointer": "^4.0.1",
- "lodash": "^4.17.15",
"nanoid": "^3.1.20",
"prop-types": "^15.7.2"
},
@@ -44,15 +38,9 @@
"react-is": "16.x"
},
"devDependencies": {
- "@babel/cli": "^7.4.4",
"@babel/core": "^7.4.5",
- "@babel/plugin-proposal-class-properties": "^7.4.4",
- "@babel/plugin-proposal-object-rest-spread": "^7.4.4",
- "@babel/plugin-transform-react-jsx": "^7.3.0",
- "@babel/plugin-transform-runtime": "^7.4.4",
"@babel/preset-env": "^7.4.5",
"@babel/preset-react": "^7.0.0",
- "@babel/register": "^7.4.4",
"@readme/eslint-config": "^4.0.0",
"@testing-library/jest-dom": "^5.11.9",
"babel-eslint": "^10.1.0",
@@ -65,9 +53,7 @@
"prettier": "^2.1.2",
"react": "^16.14.0",
"react-dom": "^16.14.0",
- "react-is": "^16.13.1",
"react-portal": "^4.2.0",
- "rimraf": "^2.5.4",
"style-loader": "^0.13.1",
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2"
diff --git a/packages/oas-form/src/components/ErrorList.js b/packages/oas-form/src/components/ErrorList.js
deleted file mode 100644
index 1e3567222..000000000
--- a/packages/oas-form/src/components/ErrorList.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-
-export default function ErrorList(props) {
- const { errors } = props;
- return (
-
-
-
Errors
-
-
- {errors.map((error, i) => {
- return (
-
- {error.stack}
-
- );
- })}
-
-
- );
-}
diff --git a/packages/oas-form/src/components/Form.js b/packages/oas-form/src/components/Form.js
index 3563b1b10..c3097605b 100644
--- a/packages/oas-form/src/components/Form.js
+++ b/packages/oas-form/src/components/Form.js
@@ -1,10 +1,6 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
-import _pick from 'lodash/pick';
-import _get from 'lodash/get';
-import _isEmpty from 'lodash/isEmpty';
-import DefaultErrorList from './ErrorList';
import {
getDefaultFormState,
retrieveSchema,
@@ -12,20 +8,12 @@ import {
toIdSchema,
getDefaultRegistry,
deepEquals,
- toPathSchema,
isObject,
- mergeObjects,
} from '../utils';
-import validateFormData, { toErrorList } from '../validate';
export default class Form extends Component {
static defaultProps = {
disabled: false,
- ErrorList: DefaultErrorList,
- liveValidate: false,
- noHtml5Validate: false,
- noValidate: false,
- omitExtraData: false,
uiSchema: {},
};
@@ -51,27 +39,12 @@ export default class Form extends Component {
}
getStateFromProps(props, inputFormData) {
- const state = this.state || {};
const schema = 'schema' in props ? props.schema : this.props.schema;
const uiSchema = 'uiSchema' in props ? props.uiSchema : this.props.uiSchema;
const edit = typeof inputFormData !== 'undefined';
- const liveValidate = props.liveValidate || this.props.liveValidate;
- const mustValidate = edit && !props.noValidate && liveValidate;
const rootSchema = schema;
const formData = getDefaultFormState(schema, inputFormData, rootSchema);
const retrievedSchema = retrieveSchema(schema, rootSchema, formData);
- const customFormats = props.customFormats;
- const additionalMetaSchemas = props.additionalMetaSchemas;
- let { errors, errorSchema } = mustValidate
- ? this.validate(formData, schema, additionalMetaSchemas, customFormats)
- : {
- errors: state.errors || [],
- errorSchema: state.errorSchema || {},
- };
- if (props.extraErrors) {
- errorSchema = mergeObjects(errorSchema, props.extraErrors);
- errors = toErrorList(errorSchema);
- }
const idSchema = toIdSchema(retrievedSchema, uiSchema['ui:rootFieldId'], rootSchema, formData, props.idPrefix);
return {
schema,
@@ -79,9 +52,6 @@ export default class Form extends Component {
idSchema,
formData,
edit,
- errors,
- errorSchema,
- additionalMetaSchemas,
};
}
@@ -89,112 +59,14 @@ export default class Form extends Component {
return shouldRender(this, nextProps, nextState);
}
- validate(
- formData,
- schema = this.props.schema,
- additionalMetaSchemas = this.props.additionalMetaSchemas,
- customFormats = this.props.customFormats
- ) {
- const { validate, transformErrors } = this.props;
- const { rootSchema } = this.getRegistry();
- const resolvedSchema = retrieveSchema(schema, rootSchema, formData);
- return validateFormData(formData, resolvedSchema, validate, transformErrors, additionalMetaSchemas, customFormats);
- }
-
- renderErrors() {
- const { errors, errorSchema, schema, uiSchema } = this.state;
- const { ErrorList, showErrorList, formContext } = this.props;
-
- if (errors.length && showErrorList !== false) {
- return (
-
- );
- }
- return null;
- }
-
- getUsedFormData = (formData, fields) => {
- // for the case of a single input form
- if (fields.length === 0 && typeof formData !== 'object') {
- return formData;
- }
-
- const data = _pick(formData, fields);
- if (Array.isArray(formData)) {
- return Object.keys(data).map(key => data[key]);
- }
-
- return data;
- };
-
- getFieldNames = (pathSchema, formData) => {
- const getAllPaths = (_obj, acc = [], paths = ['']) => {
- Object.keys(_obj).forEach(key => {
- if (typeof _obj[key] === 'object') {
- const newPaths = paths.map(path => `${path}.${key}`);
- getAllPaths(_obj[key], acc, newPaths);
- } else if (key === '$name' && _obj[key] !== '') {
- paths.forEach(path => {
- path = path.replace(/^\./, '');
- const formValue = _get(formData, path);
- // adds path to fieldNames if it points to a value
- // or an empty object/array
- if (typeof formValue !== 'object' || _isEmpty(formValue)) {
- acc.push(path);
- }
- });
- }
- });
- return acc;
- };
-
- return getAllPaths(pathSchema);
- };
-
- onChange = (formData, newErrorSchema) => {
+ onChange = formData => {
if (isObject(formData) || Array.isArray(formData)) {
const newState = this.getStateFromProps(this.props, formData);
formData = newState.formData;
}
- const mustValidate = !this.props.noValidate && this.props.liveValidate;
- let state = { formData };
- let newFormData = formData;
- if (this.props.omitExtraData === true && this.props.liveOmit === true) {
- const retrievedSchema = retrieveSchema(this.state.schema, this.state.schema, formData);
- const pathSchema = toPathSchema(retrievedSchema, '', this.state.schema, formData);
+ const state = { formData };
- const fieldNames = this.getFieldNames(pathSchema, formData);
-
- newFormData = this.getUsedFormData(formData, fieldNames);
- state = {
- formData: newFormData,
- };
- }
-
- if (mustValidate) {
- let { errors, errorSchema } = this.validate(newFormData);
- if (this.props.extraErrors) {
- errorSchema = mergeObjects(errorSchema, this.props.extraErrors);
- errors = toErrorList(errorSchema);
- }
- state = { formData: newFormData, errors, errorSchema };
- } else if (!this.props.noValidate && newErrorSchema) {
- const errorSchema = this.props.extraErrors
- ? mergeObjects(newErrorSchema, this.props.extraErrors)
- : newErrorSchema;
- state = {
- formData: newFormData,
- errorSchema,
- errors: toErrorList(errorSchema),
- };
- }
this.setState(state, () => this.props.onChange && this.props.onChange(state));
};
@@ -217,46 +89,9 @@ export default class Form extends Component {
}
event.persist();
- let newFormData = this.state.formData;
-
- if (this.props.omitExtraData === true) {
- const retrievedSchema = retrieveSchema(this.state.schema, this.state.schema, newFormData);
- const pathSchema = toPathSchema(retrievedSchema, '', this.state.schema, newFormData);
+ const newFormData = this.state.formData;
- const fieldNames = this.getFieldNames(pathSchema, newFormData);
-
- newFormData = this.getUsedFormData(newFormData, fieldNames);
- }
-
- if (!this.props.noValidate) {
- let { errors, errorSchema } = this.validate(newFormData);
- if (Object.keys(errors).length > 0) {
- if (this.props.extraErrors) {
- errorSchema = mergeObjects(errorSchema, this.props.extraErrors);
- errors = toErrorList(errorSchema);
- }
- this.setState({ errors, errorSchema }, () => {
- if (this.props.onError) {
- this.props.onError(errors);
- } else {
- console.error('Form validation failed', errors);
- }
- });
- return;
- }
- }
-
- let errorSchema;
- let errors;
- if (this.props.extraErrors) {
- errorSchema = this.props.extraErrors;
- errors = toErrorList(errorSchema);
- } else {
- errorSchema = {};
- errors = [];
- }
-
- this.setState({ formData: newFormData, errors, errorSchema }, () => {
+ this.setState({ formData: newFormData }, () => {
if (this.props.onSubmit) {
this.props.onSubmit({ ...this.state, formData: newFormData, status: 'submitted' }, event);
}
@@ -300,23 +135,17 @@ export default class Form extends Component {
method,
target,
action,
- autocomplete: deprecatedAutocomplete,
- autoComplete: currentAutoComplete,
+ autoComplete,
enctype,
acceptcharset,
- noHtml5Validate,
disabled,
formContext,
} = this.props;
- const { schema, uiSchema, formData, errorSchema, idSchema } = this.state;
+ const { schema, uiSchema, formData, idSchema } = this.state;
const registry = this.getRegistry();
const _SchemaField = registry.fields.SchemaField;
const FormTag = tagName || 'form';
- if (deprecatedAutocomplete) {
- console.warn('Using autocomplete property of Form is deprecated, use autoComplete instead.');
- }
- const autoComplete = currentAutoComplete || deprecatedAutocomplete;
return (
- {this.renderErrors()}
<_SchemaField
disabled={disabled}
- errorSchema={errorSchema}
formContext={formContext}
formData={formData}
idPrefix={idPrefix}
@@ -366,37 +192,24 @@ if (process.env.NODE_ENV !== 'production') {
Form.propTypes = {
acceptcharset: PropTypes.string,
action: PropTypes.string,
- additionalMetaSchemas: PropTypes.arrayOf(PropTypes.object),
ArrayFieldTemplate: PropTypes.elementType,
- autocomplete: PropTypes.string,
autoComplete: PropTypes.string,
className: PropTypes.string,
- customFormats: PropTypes.object,
enctype: PropTypes.string,
- ErrorList: PropTypes.func,
- extraErrors: PropTypes.object,
fields: PropTypes.objectOf(PropTypes.elementType),
FieldTemplate: PropTypes.elementType,
formContext: PropTypes.object,
formData: PropTypes.any,
id: PropTypes.string,
- liveValidate: PropTypes.bool,
method: PropTypes.string,
name: PropTypes.string,
- noHtml5Validate: PropTypes.bool,
- noValidate: PropTypes.bool,
ObjectFieldTemplate: PropTypes.elementType,
- omitExtraData: PropTypes.bool,
onChange: PropTypes.func,
- onError: PropTypes.func,
onSubmit: PropTypes.func,
schema: PropTypes.object.isRequired,
- showErrorList: PropTypes.bool,
tagName: PropTypes.elementType,
target: PropTypes.string,
- transformErrors: PropTypes.func,
uiSchema: PropTypes.object,
- validate: PropTypes.func,
widgets: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object])),
};
}
diff --git a/packages/oas-form/src/components/fields/ArrayField.js b/packages/oas-form/src/components/fields/ArrayField.js
index 905af8857..92c23abd9 100644
--- a/packages/oas-form/src/components/fields/ArrayField.js
+++ b/packages/oas-form/src/components/fields/ArrayField.js
@@ -1,7 +1,6 @@
import AddButton from '../AddButton';
import IconButton from '../IconButton';
import React, { Component } from 'react';
-import includes from 'core-js/library/fn/array/includes';
import * as types from '../../types';
import {
@@ -205,7 +204,7 @@ class ArrayField extends Component {
if (Array.isArray(itemSchema.type)) {
// While we don't yet support composite/nullable jsonschema types, it's
// future-proof to check for requirement against these.
- return !includes(itemSchema.type, 'null');
+ return !itemSchema.type.includes('null');
}
// All non-null array item types are inherently required by design
return itemSchema.type !== 'null';
@@ -284,34 +283,20 @@ class ArrayField extends Component {
}
const { onChange } = this.props;
const { keyedFormData } = this.state;
- // refs #195: revalidate to ensure properly reindexing errors
- let newErrorSchema;
- if (this.props.errorSchema) {
- newErrorSchema = {};
- const errorSchema = this.props.errorSchema;
- for (let i in errorSchema) {
- // eslint-disable-next-line radix
- i = parseInt(i);
- if (i < index) {
- newErrorSchema[i] = errorSchema[i];
- } else if (i > index) {
- newErrorSchema[i - 1] = errorSchema[i];
- }
- }
- }
+
const newKeyedFormData = keyedFormData.filter((_, i) => i !== index);
this.setState(
{
keyedFormData: newKeyedFormData,
updatedKeyedFormData: true,
},
- () => onChange(keyedToPlainFormData(newKeyedFormData), newErrorSchema)
+ () => onChange(keyedToPlainFormData(newKeyedFormData))
);
};
};
onChangeForIndex = index => {
- return (value, errorSchema) => {
+ return value => {
const { formData, onChange } = this.props;
const newFormData = formData.map((item, i) => {
// We need to treat undefined items as nulls to have validation.
@@ -319,14 +304,7 @@ class ArrayField extends Component {
const jsonValue = typeof value === 'undefined' ? null : value;
return index === i ? jsonValue : item;
});
- onChange(
- newFormData,
- errorSchema &&
- this.props.errorSchema && {
- ...this.props.errorSchema,
- [index]: errorSchema,
- }
- );
+ onChange(newFormData);
};
};
@@ -359,7 +337,6 @@ class ArrayField extends Component {
const {
schema,
uiSchema,
- errorSchema,
idSchema,
name,
required,
@@ -370,7 +347,6 @@ class ArrayField extends Component {
onBlur,
onFocus,
idPrefix,
- rawErrors,
} = this.props;
const title = schema.title === undefined ? name : schema.title;
const { ArrayFieldTemplate, rootSchema, fields, formContext } = registry;
@@ -382,7 +358,6 @@ class ArrayField extends Component {
items: this.state.keyedFormData.map((keyedItem, index) => {
const { key, item } = keyedItem;
const itemSchema = retrieveSchema(schema.items, rootSchema, item);
- const itemErrorSchema = errorSchema ? errorSchema[index] : undefined;
const itemIdPrefix = `${idSchema.$id}_${index}`;
const itemIdSchema = toIdSchema(itemSchema, itemIdPrefix, rootSchema, item, idPrefix);
return this.renderArrayFieldItem({
@@ -390,7 +365,6 @@ class ArrayField extends Component {
index,
itemSchema,
itemIdSchema,
- itemErrorSchema,
itemData: item,
itemUiSchema: uiSchema.items,
autofocus: autofocus && index === 0,
@@ -411,7 +385,6 @@ class ArrayField extends Component {
TitleField,
formContext,
formData,
- rawErrors,
registry,
};
@@ -435,7 +408,6 @@ class ArrayField extends Component {
onBlur,
onFocus,
registry = getDefaultRegistry(),
- rawErrors,
} = this.props;
const items = this.props.formData;
const { widgets, rootSchema, formContext } = registry;
@@ -459,7 +431,6 @@ class ArrayField extends Component {
onFocus={onFocus}
options={options}
placeholder={placeholder}
- rawErrors={rawErrors}
readonly={readonly}
registry={registry}
required={required}
@@ -481,7 +452,6 @@ class ArrayField extends Component {
onBlur,
onFocus,
registry = getDefaultRegistry(),
- rawErrors,
} = this.props;
const title = schema.title || name;
const items = this.props.formData;
@@ -499,7 +469,6 @@ class ArrayField extends Component {
onChange={this.onSelectChange}
onFocus={onFocus}
options={options}
- rawErrors={rawErrors}
readonly={readonly}
schema={schema}
title={title}
@@ -513,7 +482,6 @@ class ArrayField extends Component {
schema,
uiSchema,
formData,
- errorSchema,
idPrefix,
idSchema,
name,
@@ -524,7 +492,6 @@ class ArrayField extends Component {
registry = getDefaultRegistry(),
onBlur,
onFocus,
- rawErrors,
} = this.props;
const title = schema.title || name;
let items = this.props.formData;
@@ -559,7 +526,6 @@ class ArrayField extends Component {
: Array.isArray(uiSchema.items) // eslint-disable-line unicorn/no-nested-ternary
? uiSchema.items[index]
: uiSchema.items || {};
- const itemErrorSchema = errorSchema ? errorSchema[index] : undefined;
return this.renderArrayFieldItem({
key,
@@ -569,7 +535,6 @@ class ArrayField extends Component {
itemData: item,
itemUiSchema,
itemIdSchema,
- itemErrorSchema,
autofocus: autofocus && index === 0,
onBlur,
onFocus,
@@ -583,7 +548,6 @@ class ArrayField extends Component {
title,
TitleField,
formContext,
- rawErrors,
};
// Check if a custom template template was passed in
@@ -593,19 +557,7 @@ class ArrayField extends Component {
renderArrayFieldItem(props) {
let { itemSchema } = props;
- const {
- key,
- index,
- canRemove = true,
- itemData,
- itemUiSchema,
- itemIdSchema,
- itemErrorSchema,
- autofocus,
- onBlur,
- onFocus,
- rawErrors,
- } = props;
+ const { key, index, canRemove = true, itemData, itemUiSchema, itemIdSchema, autofocus, onBlur, onFocus } = props;
const { disabled, readonly, uiSchema, registry = getDefaultRegistry() } = this.props;
const {
fields: { SchemaField },
@@ -632,14 +584,12 @@ class ArrayField extends Component {
{
const selectedOption = parseInt(option, 10);
const { formData, onChange, options, registry } = this.props;
@@ -90,7 +50,6 @@ class AnyOfField extends Component {
const {
baseType,
disabled,
- errorSchema,
formData,
idPrefix,
idSchema,
@@ -141,7 +100,6 @@ class AnyOfField extends Component {
{option !== null && (
<_SchemaField
disabled={disabled}
- errorSchema={errorSchema}
formData={formData}
idPrefix={idPrefix}
idSchema={idSchema}
@@ -160,7 +118,6 @@ class AnyOfField extends Component {
AnyOfField.defaultProps = {
disabled: false,
- errorSchema: {},
idSchema: {},
uiSchema: {},
};
@@ -168,7 +125,6 @@ AnyOfField.defaultProps = {
if (process.env.NODE_ENV !== 'production') {
AnyOfField.propTypes = {
baseType: PropTypes.string,
- errorSchema: PropTypes.object,
formData: PropTypes.any,
idSchema: PropTypes.object,
options: PropTypes.arrayOf(PropTypes.object).isRequired,
diff --git a/packages/oas-form/src/components/fields/ObjectField.js b/packages/oas-form/src/components/fields/ObjectField.js
index fd80b46b4..de009dc39 100644
--- a/packages/oas-form/src/components/fields/ObjectField.js
+++ b/packages/oas-form/src/components/fields/ObjectField.js
@@ -2,13 +2,7 @@ import AddButton from '../AddButton';
import React, { Component } from 'react';
import * as types from '../../types';
-import {
- orderProperties,
- retrieveSchema,
- getDefaultRegistry,
- getUiOptions,
- ADDITIONAL_PROPERTY_FLAG,
-} from '../../utils';
+import { retrieveSchema, getDefaultRegistry, getUiOptions, ADDITIONAL_PROPERTY_FLAG } from '../../utils';
function DefaultObjectFieldTemplate(props) {
const canExpand = function canExpand() {
@@ -61,7 +55,6 @@ function DefaultObjectFieldTemplate(props) {
class ObjectField extends Component {
static defaultProps = {
disabled: false,
- errorSchema: {},
formData: {},
idSchema: {},
readonly: false,
@@ -80,7 +73,7 @@ class ObjectField extends Component {
}
onPropertyChange = (name, addedByAdditionalProperties = false) => {
- return (value, errorSchema) => {
+ return value => {
if (!value && addedByAdditionalProperties) {
// Don't set value = undefined for fields added by
// additionalProperties. Doing so removes them from the
@@ -92,14 +85,7 @@ class ObjectField extends Component {
value = '';
}
const newFormData = { ...this.props.formData, [name]: value };
- this.props.onChange(
- newFormData,
- errorSchema &&
- this.props.errorSchema && {
- ...this.props.errorSchema,
- [name]: errorSchema,
- }
- );
+ this.props.onChange(newFormData);
};
};
@@ -123,7 +109,7 @@ class ObjectField extends Component {
};
onKeyChange = oldValue => {
- return (value, errorSchema) => {
+ return value => {
if (oldValue === value) {
return;
}
@@ -139,14 +125,7 @@ class ObjectField extends Component {
this.setState({ wasPropertyKeyModified: true });
- this.props.onChange(
- renamedObj,
- errorSchema &&
- this.props.errorSchema && {
- ...this.props.errorSchema,
- [value]: errorSchema,
- }
- );
+ this.props.onChange(renamedObj);
};
};
@@ -194,7 +173,6 @@ class ObjectField extends Component {
const {
uiSchema,
formData,
- errorSchema,
idSchema,
name,
required,
@@ -219,21 +197,7 @@ class ObjectField extends Component {
}
const description = uiSchema['ui:description'] || schema.description;
- let orderedProperties;
- try {
- const properties = Object.keys(schema.properties || {});
- orderedProperties = orderProperties(properties, uiSchema['ui:order']);
- } catch (err) {
- return (
-
-
- Invalid {name || 'root'} object field configuration:
- {err.message} .
-
-
{JSON.stringify(schema)}
-
- );
- }
+ const properties = Object.keys(schema.properties || {});
const Template = uiSchema['ui:ObjectFieldTemplate'] || registry.ObjectFieldTemplate || DefaultObjectFieldTemplate;
@@ -242,14 +206,13 @@ class ObjectField extends Component {
description,
TitleField,
DescriptionField,
- properties: orderedProperties.map(prop => {
+ properties: properties.map(prop => {
const addedByAdditionalProperties = schema.properties[prop].hasOwnProperty(ADDITIONAL_PROPERTY_FLAG);
return {
content: (
{help};
}
-function ErrorList(props) {
- const { errors = [] } = props;
- if (errors.length === 0) {
- return null;
- }
-
- return (
-
-
- {errors
- .filter(elem => !!elem)
- .map((error, index) => {
- return (
-
- {error}
-
- );
- })}
-
-
- );
-}
function DefaultTemplate(props) {
- const { id, label, children, errors, help, description, hidden, required, displayLabel } = props;
+ const { id, label, children, help, description, hidden, required, displayLabel } = props;
if (hidden) {
return {children}
;
}
@@ -124,7 +102,6 @@ function DefaultTemplate(props) {
{displayLabel && }
{displayLabel && description ? description : null}
{children}
- {errors}
{help}
);
@@ -136,7 +113,6 @@ if (process.env.NODE_ENV !== 'production') {
classNames: PropTypes.string,
description: PropTypes.element,
displayLabel: PropTypes.bool,
- errors: PropTypes.element,
fields: PropTypes.object,
formContext: PropTypes.object,
help: PropTypes.element,
@@ -144,7 +120,6 @@ if (process.env.NODE_ENV !== 'production') {
id: PropTypes.string,
label: PropTypes.string,
rawDescription: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
- rawErrors: PropTypes.arrayOf(PropTypes.string),
rawHelp: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
readonly: PropTypes.bool,
required: PropTypes.bool,
@@ -197,7 +172,6 @@ function SchemaFieldRender(props) {
const {
uiSchema,
formData,
- errorSchema,
idPrefix,
name,
onKeyChange,
@@ -241,18 +215,14 @@ function SchemaFieldRender(props) {
displayLabel = false;
}
- const { __errors, ...fieldErrorSchema } = errorSchema;
-
// See #439: uiSchema: Don't pass consumed class names to child components
const field = (
0 ? 'field-error has-error has-danger' : '',
- uiSchema.classNames,
- ]
- .join(' ')
- .trim();
+ const classNames = ['form-group', 'field', `field-${type}`, uiSchema.classNames].join(' ').trim();
const fieldProps = {
description: ,
rawDescription: description,
help: ,
rawHelp: typeof help === 'string' ? help : undefined,
- errors: ,
- rawErrors: errors,
id,
label,
hidden,
@@ -323,7 +282,6 @@ function SchemaFieldRender(props) {
<_AnyOfField
baseType={schema.type}
disabled={disabled}
- errorSchema={errorSchema}
formData={formData}
idPrefix={idPrefix}
idSchema={idSchema}
@@ -341,7 +299,6 @@ function SchemaFieldRender(props) {
<_OneOfField
baseType={schema.type}
disabled={disabled}
- errorSchema={errorSchema}
formData={formData}
idPrefix={idPrefix}
idSchema={idSchema}
@@ -371,7 +328,6 @@ class SchemaField extends React.Component {
SchemaField.defaultProps = {
autofocus: false,
disabled: false,
- errorSchema: {},
idSchema: {},
readonly: false,
uiSchema: {},
@@ -379,7 +335,6 @@ SchemaField.defaultProps = {
if (process.env.NODE_ENV !== 'production') {
SchemaField.propTypes = {
- errorSchema: PropTypes.object,
formData: PropTypes.any,
idSchema: PropTypes.object,
registry: types.registry.isRequired,
diff --git a/packages/oas-form/src/components/fields/StringField.js b/packages/oas-form/src/components/fields/StringField.js
index f9f5e9b55..8666b5f68 100644
--- a/packages/oas-form/src/components/fields/StringField.js
+++ b/packages/oas-form/src/components/fields/StringField.js
@@ -18,7 +18,6 @@ function StringField(props) {
onBlur,
onFocus,
registry = getDefaultRegistry(),
- rawErrors,
} = props;
const { title, format } = schema;
const { widgets, formContext } = registry;
@@ -58,7 +57,6 @@ function StringField(props) {
onFocus={onFocus}
options={{ ...options, enumOptions }}
placeholder={placeholder}
- rawErrors={rawErrors}
readonly={readonly}
registry={registry}
required={required}
diff --git a/packages/oas-form/src/components/widgets/BaseInput.js b/packages/oas-form/src/components/widgets/BaseInput.js
index 1cb322930..b9841d38c 100644
--- a/packages/oas-form/src/components/widgets/BaseInput.js
+++ b/packages/oas-form/src/components/widgets/BaseInput.js
@@ -19,7 +19,6 @@ function BaseInput(props) {
schema,
formContext,
registry,
- rawErrors,
...inputProps
} = props;
diff --git a/packages/oas-form/src/index.js b/packages/oas-form/src/index.js
index 84fad2d2f..f1beeba22 100644
--- a/packages/oas-form/src/index.js
+++ b/packages/oas-form/src/index.js
@@ -1,5 +1,3 @@
import Form from './components/Form';
-import withTheme from './withTheme';
-export { withTheme };
export default Form;
diff --git a/packages/oas-form/src/types.js b/packages/oas-form/src/types.js
index 6053c09d6..9eb5c8d1a 100644
--- a/packages/oas-form/src/types.js
+++ b/packages/oas-form/src/types.js
@@ -14,13 +14,11 @@ export const registry = PropTypes.shape({
export const fieldProps = {
autofocus: PropTypes.bool,
disabled: PropTypes.bool,
- errorSchema: PropTypes.object,
formData: PropTypes.any,
idSchema: PropTypes.object,
onBlur: PropTypes.func,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
- rawErrors: PropTypes.arrayOf(PropTypes.string),
readonly: PropTypes.bool,
registry: registry.isRequired,
required: PropTypes.bool,
diff --git a/packages/oas-form/src/utils.js b/packages/oas-form/src/utils.js
index 6a3464bfd..4b02c46fe 100644
--- a/packages/oas-form/src/utils.js
+++ b/packages/oas-form/src/utils.js
@@ -1,9 +1,5 @@
import React from 'react';
-import * as ReactIs from 'react-is';
import mergeAllOf from 'json-schema-merge-allof';
-import fill from 'core-js/library/fn/array/fill';
-import validateFormData, { isValid } from './validate';
-import union from 'lodash/union';
import jsonpointer from 'jsonpointer';
export const ADDITIONAL_PROPERTY_FLAG = '__additional_property';
@@ -187,7 +183,7 @@ export function getWidget(schema, widget, registeredWidgets = {}) {
return Widget.MergedWidget;
}
- if (typeof widget === 'function' || ReactIs.isForwardRef(React.createElement(widget)) || ReactIs.isMemo(widget)) {
+ if (typeof widget === 'function') {
return mergeOptions(widget);
}
@@ -246,9 +242,6 @@ function computeDefaults(_schema, parentDefaults, rootSchema, rawFormData = {},
}
return computeDefaults(refSchema, defaults, rootSchema, formData, includeUndefinedValues);
- } else if ('dependencies' in schema) {
- const resolvedSchema = resolveDependencies(schema, rootSchema, formData);
- return computeDefaults(resolvedSchema, defaults, rootSchema, formData, includeUndefinedValues);
} else if (isFixedItems(schema)) {
defaults = schema.items.map((itemSchema, idx) =>
computeDefaults(
@@ -260,9 +253,9 @@ function computeDefaults(_schema, parentDefaults, rootSchema, rawFormData = {},
)
);
} else if ('oneOf' in schema) {
- schema = schema.oneOf[getMatchingOption(undefined, schema.oneOf)];
+ schema = schema.oneOf[0];
} else if ('anyOf' in schema) {
- schema = schema.anyOf[getMatchingOption(undefined, schema.anyOf)];
+ schema = schema.anyOf[0];
}
// Not defaults defined for this node, fallback to generic typed ones.
@@ -310,8 +303,7 @@ function computeDefaults(_schema, parentDefaults, rootSchema, rawFormData = {},
const defaultEntries = defaults || [];
// populate the array with the defaults
const fillerSchema = Array.isArray(schema.items) ? schema.additionalItems : schema.items;
- const fillerEntries = fill(
- new Array(schema.minItems - defaultsLength),
+ const fillerEntries = new Array(schema.minItems - defaultsLength).fill(
computeDefaults(fillerSchema, fillerSchema.defaults, rootSchema)
);
// then fill up the rest with either the item default or empty, up to minItems
@@ -451,38 +443,6 @@ export function asNumber(value) {
return valid ? n : value;
}
-export function orderProperties(properties, order) {
- if (!Array.isArray(order)) {
- return properties;
- }
-
- const arrayToHash = arr =>
- arr.reduce((prev, curr) => {
- prev[curr] = true;
- return prev;
- }, {});
- const errorPropList = arr => (arr.length > 1 ? `properties '${arr.join("', '")}'` : `property '${arr[0]}'`);
- const propertyHash = arrayToHash(properties);
- const orderFiltered = order.filter(prop => prop === '*' || propertyHash[prop]);
- const orderHash = arrayToHash(orderFiltered);
-
- const rest = properties.filter(prop => !orderHash[prop]);
- const restIndex = orderFiltered.indexOf('*');
- if (restIndex === -1) {
- if (rest.length) {
- throw new Error(`uiSchema order list does not contain ${errorPropList(rest)}`);
- }
- return orderFiltered;
- }
- if (restIndex !== orderFiltered.lastIndexOf('*')) {
- throw new Error('uiSchema order list contains more than one wildcard item');
- }
-
- const complete = [...orderFiltered];
- complete.splice(restIndex, 1, ...rest);
- return complete;
-}
-
/**
* This function checks if the given schema matches a single
* constant value.
@@ -629,9 +589,6 @@ export function stubExistingAdditionalProperties(schema, rootSchema = {}, formDa
export function resolveSchema(schema, rootSchema = {}, formData = {}) {
if (schema.hasOwnProperty('$ref')) {
return resolveReference(schema, rootSchema, formData);
- } else if (schema.hasOwnProperty('dependencies')) {
- const resolvedSchema = resolveDependencies(schema, rootSchema, formData);
- return retrieveSchema(resolvedSchema, rootSchema, formData);
} else if (schema.hasOwnProperty('allOf')) {
return {
...schema,
@@ -639,7 +596,7 @@ export function resolveSchema(schema, rootSchema = {}, formData = {}) {
};
}
- // No $ref or dependencies attribute found, returning the original schema.
+ // No $ref or allOf attribute found, returning the original schema.
return schema;
}
@@ -691,124 +648,6 @@ export function retrieveSchema(schema, rootSchema = {}, formData = {}) {
return resolvedSchema;
}
-function resolveDependencies(schema, rootSchema, formData) {
- // Drop the dependencies from the source schema.
- // eslint-disable-next-line prefer-const
- let { dependencies = {}, ...resolvedSchema } = schema;
- if ('oneOf' in resolvedSchema) {
- resolvedSchema = resolvedSchema.oneOf[getMatchingOption(formData, resolvedSchema.oneOf)];
- } else if ('anyOf' in resolvedSchema) {
- resolvedSchema = resolvedSchema.anyOf[getMatchingOption(formData, resolvedSchema.anyOf)];
- }
- return processDependencies(dependencies, resolvedSchema, rootSchema, formData);
-}
-
-function processDependencies(dependencies, resolvedSchema, rootSchema, formData) {
- // Process dependencies updating the local schema properties as appropriate.
- for (const dependencyKey in dependencies) {
- // Skip this dependency if its trigger property is not present.
- if (formData[dependencyKey] === undefined) {
- continue; // eslint-disable-line no-continue
- }
- // Skip this dependency if it is not included in the schema (such as when dependencyKey is itself a hidden dependency.)
- if (resolvedSchema.properties && !(dependencyKey in resolvedSchema.properties)) {
- continue; // eslint-disable-line no-continue
- }
- const { [dependencyKey]: dependencyValue, ...remainingDependencies } = dependencies;
- if (Array.isArray(dependencyValue)) {
- resolvedSchema = withDependentProperties(resolvedSchema, dependencyValue);
- } else if (isObject(dependencyValue)) {
- resolvedSchema = withDependentSchema(resolvedSchema, rootSchema, formData, dependencyKey, dependencyValue);
- }
- return processDependencies(remainingDependencies, resolvedSchema, rootSchema, formData);
- }
- return resolvedSchema;
-}
-
-function withDependentProperties(schema, additionallyRequired) {
- if (!additionallyRequired) {
- return schema;
- }
- const required = Array.isArray(schema.required)
- ? Array.from(new Set([...schema.required, ...additionallyRequired]))
- : additionallyRequired;
- return { ...schema, required };
-}
-
-function withDependentSchema(schema, rootSchema, formData, dependencyKey, dependencyValue) {
- const { oneOf, ...dependentSchema } = retrieveSchema(dependencyValue, rootSchema, formData);
- schema = mergeSchemas(schema, dependentSchema);
- // Since it does not contain oneOf, we return the original schema.
- if (oneOf === undefined) {
- return schema;
- } else if (!Array.isArray(oneOf)) {
- throw new TypeError(`invalid: it is some ${typeof oneOf} instead of an array`);
- }
- // Resolve $refs inside oneOf.
- const resolvedOneOf = oneOf.map(subschema =>
- subschema.hasOwnProperty('$ref') ? resolveReference(subschema, rootSchema, formData) : subschema
- );
- return withExactlyOneSubschema(schema, rootSchema, formData, dependencyKey, resolvedOneOf);
-}
-
-function withExactlyOneSubschema(schema, rootSchema, formData, dependencyKey, oneOf) {
- // eslint-disable-next-line array-callback-return, consistent-return
- const validSubschemas = oneOf.filter(subschema => {
- if (!subschema.properties) {
- return false;
- }
- const { [dependencyKey]: conditionPropertySchema } = subschema.properties;
- if (conditionPropertySchema) {
- const conditionSchema = {
- type: 'object',
- properties: {
- [dependencyKey]: conditionPropertySchema,
- },
- };
- const { errors } = validateFormData(formData, conditionSchema);
- return errors.length === 0;
- }
- });
- if (validSubschemas.length !== 1) {
- console.warn("ignoring oneOf in dependencies because there isn't exactly one subschema that is valid");
- return schema;
- }
- const subschema = validSubschemas[0];
- const { [dependencyKey]: conditionPropertySchema, ...dependentSubschema } = subschema.properties;
- const dependentSchema = { ...subschema, properties: dependentSubschema };
- return mergeSchemas(schema, retrieveSchema(dependentSchema, rootSchema, formData));
-}
-
-// Recursively merge deeply nested schemas.
-// The difference between mergeSchemas and mergeObjects
-// is that mergeSchemas only concats arrays for
-// values under the "required" keyword, and when it does,
-// it doesn't include duplicate values.
-export function mergeSchemas(obj1, obj2) {
- const acc = { ...obj1 }; // Prevent mutation of source object.
- return Object.keys(obj2).reduce((acc2, key) => {
- const left = obj1 ? obj1[key] : {};
- const right = obj2[key];
- if (obj1 && obj1.hasOwnProperty(key) && isObject(right)) {
- acc2[key] = mergeSchemas(left, right);
- } else if (
- obj1 &&
- obj2 &&
- (getSchemaType(obj1) === 'object' || getSchemaType(obj2) === 'object') &&
- key === 'required' &&
- Array.isArray(left) &&
- Array.isArray(right)
- ) {
- // Don't include duplicate values when merging
- // "required" fields.
- acc2[key] = union(left, right);
- } else {
- acc2[key] = right;
- }
- return acc2;
- }, acc);
-}
-
function isArguments(object) {
return Object.prototype.toString.call(object) === '[object Arguments]';
}
@@ -904,7 +743,7 @@ export function toIdSchema(schema, id, rootSchema, formData = {}, idPrefix = 'ro
return idSchema;
}
- if ('$ref' in schema || 'dependencies' in schema || 'allOf' in schema) {
+ if ('$ref' in schema || 'allOf' in schema) {
const _schema = retrieveSchema(schema, rootSchema, formData);
return toIdSchema(_schema, id, rootSchema, formData, idPrefix);
}
@@ -930,33 +769,6 @@ export function toIdSchema(schema, id, rootSchema, formData = {}, idPrefix = 'ro
return idSchema;
}
-export function toPathSchema(schema, name = '', rootSchema, formData = {}) {
- const pathSchema = {
- $name: name.replace(/^\./, ''),
- };
- if ('$ref' in schema || 'dependencies' in schema || 'allOf' in schema) {
- const _schema = retrieveSchema(schema, rootSchema, formData);
- return toPathSchema(_schema, name, rootSchema, formData);
- }
- if (schema.hasOwnProperty('items') && Array.isArray(formData)) {
- formData.forEach((element, i) => {
- pathSchema[i] = toPathSchema(schema.items, `${name}.${i}`, rootSchema, element);
- });
- } else if (schema.hasOwnProperty('properties')) {
- for (const property in schema.properties) {
- pathSchema[property] = toPathSchema(
- schema.properties[property],
- `${name}.${property}`,
- rootSchema,
- // It's possible that formData is not an object -- this can happen if an
- // array item has just been added, but not populated with data yet
- (formData || {})[property]
- );
- }
- }
- return pathSchema;
-}
-
export function parseDateString(dateString, includeTime = true) {
if (!dateString) {
return {
@@ -1042,58 +854,3 @@ export function rangeSpec(schema) {
}
return spec;
}
-
-export function getMatchingOption(formData, options) {
- for (let i = 0; i < options.length; i++) {
- const option = options[i];
-
- // If the schema describes an object then we need to add slightly more
- // strict matching to the schema, because unless the schema uses the
- // "requires" keyword, an object will match the schema as long as it
- // doesn't have matching keys with a conflicting type. To do this we use an
- // "anyOf" with an array of requires. This augmentation expresses that the
- // schema should match if any of the keys in the schema are present on the
- // object and pass validation.
- if (option.properties) {
- // Create an "anyOf" schema that requires at least one of the keys in the
- // "properties" object
- const requiresAnyOf = {
- anyOf: Object.keys(option.properties).map(key => ({
- required: [key],
- })),
- };
-
- let augmentedSchema;
-
- // If the "anyOf" keyword already exists, wrap the augmentation in an "allOf"
- if (option.anyOf) {
- // Create a shallow clone of the option
- const { ...shallowClone } = option;
-
- if (!shallowClone.allOf) {
- shallowClone.allOf = [];
- } else {
- // If "allOf" already exists, shallow clone the array
- shallowClone.allOf = shallowClone.allOf.slice();
- }
-
- shallowClone.allOf.push(requiresAnyOf);
-
- augmentedSchema = shallowClone;
- } else {
- augmentedSchema = { ...option, ...requiresAnyOf };
- }
-
- // Remove the "required" field as it's likely that not all fields have
- // been filled in yet, which will mean that the schema is not valid
- delete augmentedSchema.required;
-
- if (isValid(augmentedSchema, formData)) {
- return i;
- }
- } else if (isValid(options[i], formData)) {
- return i;
- }
- }
- return 0;
-}
diff --git a/packages/oas-form/src/validate.js b/packages/oas-form/src/validate.js
deleted file mode 100644
index d5d7836cb..000000000
--- a/packages/oas-form/src/validate.js
+++ /dev/null
@@ -1,268 +0,0 @@
-/* eslint-disable unicorn/no-unsafe-regex */
-import toPath from 'lodash/toPath';
-import Ajv from 'ajv';
-import { deepEquals, getDefaultFormState, isObject, mergeObjects } from './utils';
-
-let ajv = createAjvInstance();
-
-let formerCustomFormats = null;
-let formerMetaSchema = null;
-
-function createAjvInstance() {
- const ajv = new Ajv({
- errorDataPath: 'property',
- allErrors: true,
- multipleOfPrecision: 8,
- schemaId: 'auto',
- unknownFormats: 'ignore',
- });
-
- // add custom formats
- ajv.addFormat('data-url', /^data:([a-z]+\/[a-z0-9-+.]+)?;(?:name=(.*);)?base64,(.*)$/);
- ajv.addFormat(
- 'color',
- /^(#?([0-9A-Fa-f]{3}){1,2}\b|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow|(rgb\(\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*\))|(rgb\(\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*\)))$/
- );
- return ajv;
-}
-
-function toErrorSchema(errors) {
- // Transforms a ajv validation errors list:
- // [
- // {property: ".level1.level2[2].level3", message: "err a"},
- // {property: ".level1.level2[2].level3", message: "err b"},
- // {property: ".level1.level2[4].level3", message: "err b"},
- // ]
- // Into an error tree:
- // {
- // level1: {
- // level2: {
- // 2: {level3: {errors: ["err a", "err b"]}},
- // 4: {level3: {errors: ["err b"]}},
- // }
- // }
- // };
- if (!errors.length) {
- return {};
- }
- return errors.reduce((errorSchema, error) => {
- const { property, message } = error;
- const path = toPath(property);
- let parent = errorSchema;
-
- // If the property is at the root (.level1) then toPath creates
- // an empty array element at the first index. Remove it.
- if (path.length > 0 && path[0] === '') {
- path.splice(0, 1);
- }
-
- for (const segment of path.slice(0)) {
- if (!(segment in parent)) {
- parent[segment] = {};
- }
- parent = parent[segment];
- }
-
- if (Array.isArray(parent.__errors)) {
- // We store the list of errors for this node in a property named __errors
- // to avoid name collision with a possible sub schema field named
- // "errors" (see `validate.createErrorHandler`).
- parent.__errors = parent.__errors.concat(message);
- } else if (message) {
- parent.__errors = [message];
- }
- return errorSchema;
- }, {});
-}
-
-export function toErrorList(errorSchema, fieldName = 'root') {
- // XXX: We should transform fieldName as a full field path string.
- let errorList = [];
- if ('__errors' in errorSchema) {
- errorList = errorList.concat(
- errorSchema.__errors.map(stack => {
- return {
- stack: `${fieldName}: ${stack}`,
- };
- })
- );
- }
- return Object.keys(errorSchema).reduce((acc, key) => {
- if (key !== '__errors') {
- acc = acc.concat(toErrorList(errorSchema[key], key));
- }
- return acc;
- }, errorList);
-}
-
-function createErrorHandler(formData) {
- const handler = {
- // We store the list of errors for this node in a property named __errors
- // to avoid name collision with a possible sub schema field named
- // "errors" (see `utils.toErrorSchema`).
- __errors: [],
- addError(message) {
- this.__errors.push(message);
- },
- };
- if (isObject(formData)) {
- return Object.keys(formData).reduce((acc, key) => {
- return { ...acc, [key]: createErrorHandler(formData[key]) };
- }, handler);
- }
- if (Array.isArray(formData)) {
- return formData.reduce((acc, value, key) => {
- return { ...acc, [key]: createErrorHandler(value) };
- }, handler);
- }
- return handler;
-}
-
-function unwrapErrorHandler(errorHandler) {
- return Object.keys(errorHandler).reduce((acc, key) => {
- if (key === 'addError') {
- return acc;
- } else if (key === '__errors') {
- return { ...acc, [key]: errorHandler[key] };
- }
- return { ...acc, [key]: unwrapErrorHandler(errorHandler[key]) };
- }, {});
-}
-
-/**
- * Transforming the error output from ajv to format used by jsonschema.
- * At some point, components should be updated to support ajv.
- */
-function transformAjvErrors(errors = []) {
- if (errors === null) {
- return [];
- }
-
- return errors.map(e => {
- const { dataPath, keyword, message, params, schemaPath } = e;
- const property = `${dataPath}`;
-
- // put data in expected format
- return {
- name: keyword,
- property,
- message,
- params, // specific to ajv
- stack: `${property} ${message}`.trim(),
- schemaPath,
- };
- });
-}
-
-/**
- * This function processes the formData with a user `validate` contributed
- * function, which receives the form data and an `errorHandler` object that
- * will be used to add custom validation errors for each field.
- */
-export default function validateFormData(
- formData,
- schema,
- customValidate,
- transformErrors,
- additionalMetaSchemas = [],
- customFormats = {}
-) {
- // Include form data with undefined values, which is required for validation.
- const rootSchema = schema;
- formData = getDefaultFormState(schema, formData, rootSchema, true);
-
- const newMetaSchemas = !deepEquals(formerMetaSchema, additionalMetaSchemas);
- const newFormats = !deepEquals(formerCustomFormats, customFormats);
-
- if (newMetaSchemas || newFormats) {
- ajv = createAjvInstance();
- }
-
- // add more schemas to validate against
- if (additionalMetaSchemas && newMetaSchemas && Array.isArray(additionalMetaSchemas)) {
- ajv.addMetaSchema(additionalMetaSchemas);
- formerMetaSchema = additionalMetaSchemas;
- }
-
- // add more custom formats to validate against
- if (customFormats && newFormats && isObject(customFormats)) {
- Object.keys(customFormats).forEach(formatName => {
- ajv.addFormat(formatName, customFormats[formatName]);
- });
-
- formerCustomFormats = customFormats;
- }
-
- let validationError = null;
- try {
- ajv.validate(schema, formData);
- } catch (err) {
- validationError = err;
- }
-
- let errors = transformAjvErrors(ajv.errors);
- // Clear errors to prevent persistent errors, see #1104
-
- ajv.errors = null;
-
- const noProperMetaSchema =
- validationError &&
- validationError.message &&
- typeof validationError.message === 'string' &&
- validationError.message.includes('no schema with key or ref ');
-
- if (noProperMetaSchema) {
- errors = [
- ...errors,
- {
- stack: validationError.message,
- },
- ];
- }
- if (typeof transformErrors === 'function') {
- errors = transformErrors(errors);
- }
-
- let errorSchema = toErrorSchema(errors);
-
- if (noProperMetaSchema) {
- errorSchema = {
- ...errorSchema,
- ...{
- $schema: {
- __errors: [validationError.message],
- },
- },
- };
- }
-
- if (typeof customValidate !== 'function') {
- return { errors, errorSchema };
- }
-
- const errorHandler = customValidate(formData, createErrorHandler(formData));
- const userErrorSchema = unwrapErrorHandler(errorHandler);
- const newErrorSchema = mergeObjects(errorSchema, userErrorSchema, true);
- // XXX: The errors list produced is not fully compliant with the format
- // exposed by the jsonschema lib, which contains full field paths and other
- // properties.
- const newErrors = toErrorList(newErrorSchema);
-
- return {
- errors: newErrors,
- errorSchema: newErrorSchema,
- };
-}
-
-/**
- * Validates data against a schema, returning true if the data is valid, or
- * false otherwise. If the schema is invalid, then this function will return
- * false.
- */
-export function isValid(schema, data) {
- try {
- return ajv.validate(schema, data);
- } catch (e) {
- return false;
- }
-}
diff --git a/packages/oas-form/src/withTheme.js b/packages/oas-form/src/withTheme.js
deleted file mode 100644
index 67b0ddb2d..000000000
--- a/packages/oas-form/src/withTheme.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React, { forwardRef } from 'react';
-import PropTypes from 'prop-types';
-import Form from '.';
-
-function withTheme(themeProps) {
- return forwardRef(({ fields, widgets, ...directProps }, ref) => {
- fields = { ...themeProps.fields, ...fields };
- widgets = { ...themeProps.widgets, ...widgets };
-
- return ;
- });
-}
-
-withTheme.propTypes = {
- fields: PropTypes.object,
- widgets: PropTypes.object,
-};
-
-export default withTheme;
diff --git a/packages/oas-form/webpack.config.dist.js b/packages/oas-form/webpack.config.js
similarity index 80%
rename from packages/oas-form/webpack.config.dist.js
rename to packages/oas-form/webpack.config.js
index 4c4e231df..31f98769c 100644
--- a/packages/oas-form/webpack.config.dist.js
+++ b/packages/oas-form/webpack.config.js
@@ -39,12 +39,13 @@ module.exports = {
module: {
rules: [
{
- test: /\.js$/,
- use: ['babel-loader'],
- exclude: [
- path.join(__dirname, 'node_modules', 'core-js'),
- path.join(__dirname, 'node_modules', 'babel-runtime'),
- ],
+ test: /\.js(x?)$/,
+ use: {
+ loader: 'babel-loader',
+ options: {
+ extends: '../../.babelrc',
+ },
+ },
},
],
},