diff --git a/package-lock.json b/package-lock.json index 93b4c9d425..8fb7b5777e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,8 @@ "@babel/preset-react": "^7.6.3", "@babel/preset-typescript": "^7.6.0", "@babel/runtime": "^7.6.3", + "@testing-library/react": "^11.0.4", + "@testing-library/user-event": "^14.3.0", "@types/classnames": "^2.2.9", "@types/lodash": "^4.14.144", "@types/react": "^16.0.0", @@ -1637,6 +1639,92 @@ "node": ">=8" } }, + "node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@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", @@ -1742,6 +1830,131 @@ "node": ">= 0.6.0" } }, + "node_modules/@testing-library/dom": { + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.6", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@testing-library/dom/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/react": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.7.tgz", + "integrity": "sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^7.28.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.3.0.tgz", + "integrity": "sha512-P02xtBBa8yMaLhK8CzJCIns8rqwnF6FxhR9zs810flHOBXUYCFjLd8Io1rQrAkQRWEmW2PGdZIEdMxf/KLsqFA==", + "dev": true, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, "node_modules/@types/classnames": { "version": "2.2.11", "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.11.tgz", @@ -1846,6 +2059,30 @@ "@types/node": "*" } }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -1938,6 +2175,21 @@ "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==", "dev": true }, + "node_modules/@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "4.19.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.19.0.tgz", @@ -4451,6 +4703,12 @@ "node": ">=6.0.0" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.14", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz", + "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==", + "dev": true + }, "node_modules/dom-helpers": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", @@ -8373,6 +8631,15 @@ "node": ">=10" } }, + "node_modules/lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -9848,6 +10115,60 @@ "node": ">=6.0.0" } }, + "node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pretty-format/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -15211,6 +15532,70 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.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", @@ -15304,6 +15689,96 @@ "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==", "dev": true }, + "@testing-library/dom": { + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.6", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@testing-library/react": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.7.tgz", + "integrity": "sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^7.28.1" + } + }, + "@testing-library/user-event": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.3.0.tgz", + "integrity": "sha512-P02xtBBa8yMaLhK8CzJCIns8rqwnF6FxhR9zs810flHOBXUYCFjLd8Io1rQrAkQRWEmW2PGdZIEdMxf/KLsqFA==", + "dev": true, + "requires": {} + }, + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, "@types/classnames": { "version": "2.2.11", "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.11.tgz", @@ -15408,6 +15883,30 @@ "@types/node": "*" } }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, "@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -15500,6 +15999,21 @@ "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==", "dev": true }, + "@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "4.19.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.19.0.tgz", @@ -17488,6 +18002,12 @@ "esutils": "^2.0.2" } }, + "dom-accessibility-api": { + "version": "0.5.14", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz", + "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==", + "dev": true + }, "dom-helpers": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", @@ -20532,6 +21052,12 @@ "yallist": "^4.0.0" } }, + "lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", + "dev": true + }, "make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -21660,6 +22186,50 @@ "fast-diff": "^1.1.2" } }, + "pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + } + } + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", diff --git a/package.json b/package.json index bf4f3ed121..ebae4ca875 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,8 @@ "@babel/preset-react": "^7.6.3", "@babel/preset-typescript": "^7.6.0", "@babel/runtime": "^7.6.3", + "@testing-library/react": "^11.0.4", + "@testing-library/user-event": "^14.3.0", "@types/classnames": "^2.2.9", "@types/lodash": "^4.14.144", "@types/react": "^16.0.0", diff --git a/src/polar/Pie.tsx b/src/polar/Pie.tsx index 9839156036..c9c23add43 100644 --- a/src/polar/Pie.tsx +++ b/src/polar/Pie.tsx @@ -121,11 +121,16 @@ interface State { prevSectors?: PieSectorDataItem[]; curSectors?: PieSectorDataItem[]; prevAnimationId?: number; + sectorToFocus?: number; } export type Props = PresentationAttributesAdaptChildEvent & PieProps; export class Pie extends PureComponent { + pieRef: HTMLElement = null; + + sectorRefs: HTMLElement[] = []; + static displayName = 'Pie'; static defaultProps = { @@ -294,6 +299,7 @@ export class Pie extends PureComponent { isAnimationFinished: !props.isAnimationActive, prevIsAnimationActive: props.isAnimationActive, prevAnimationId: props.animationId, + sectorToFocus: 0, }; } @@ -471,10 +477,10 @@ export class Pie extends PureComponent { return option(props); } if (_.isPlainObject(option)) { - return ; + return ; } - return ; + return ; } renderSectorsStatically(sectors: PieSectorDataItem[]) { @@ -489,6 +495,12 @@ export class Pie extends PureComponent { return ( { + if (ref && !this.sectorRefs.includes(ref)) { + this.sectorRefs.push(ref); + } + }} + tabIndex={-1} className="recharts-pie-sector" {...adaptEventsOfChild(this.props, entry, i)} key={`sector-${i}`} // eslint-disable-line react/no-array-index-key @@ -555,6 +567,39 @@ export class Pie extends PureComponent { ); } + attachKeyboardHandlers(pieRef: HTMLElement) { + // eslint-disable-next-line no-param-reassign + pieRef.onkeydown = (e: KeyboardEvent) => { + if (!e.altKey) { + switch (e.key) { + case 'ArrowLeft': { + const next = ++this.state.sectorToFocus % this.sectorRefs.length; + (this.sectorRefs[next] as HTMLElement).focus(); + this.setState({ sectorToFocus: next }); + break; + } + case 'ArrowRight': { + const next = + --this.state.sectorToFocus < 0 + ? this.sectorRefs.length - 1 + : this.state.sectorToFocus % this.sectorRefs.length; + (this.sectorRefs[next] as HTMLElement).focus(); + this.setState({ sectorToFocus: next }); + break; + } + case 'Escape': { + (this.sectorRefs[this.state.sectorToFocus] as HTMLElement).blur(); + this.setState({ sectorToFocus: 0 }); + break; + } + default: { + // There is nothing to do here + } + } + } + }; + } + renderSectors() { const { sectors, isAnimationActive } = this.props; const { prevSectors } = this.state; @@ -565,6 +610,12 @@ export class Pie extends PureComponent { return this.renderSectorsStatically(sectors); } + componentDidMount(): void { + if (this.pieRef) { + this.attachKeyboardHandlers(this.pieRef); + } + } + render() { const { hide, sectors, className, label, cx, cy, innerRadius, outerRadius, isAnimationActive } = this.props; const { isAnimationFinished } = this.state; @@ -584,7 +635,13 @@ export class Pie extends PureComponent { const layerClass = classNames('recharts-pie', className); return ( - + { + this.pieRef = ref; + }} + > {this.renderSectors()} {label && this.renderLabels(sectors)} {Label.renderCallByParent(this.props, null, false)} diff --git a/test/specs/polar/PieSpec.js b/test/specs/polar/PieSpec.js index f2131568e0..a59d36ded1 100644 --- a/test/specs/polar/PieSpec.js +++ b/test/specs/polar/PieSpec.js @@ -1,362 +1,438 @@ import React from 'react'; import { expect } from 'chai'; import { Surface, Pie, Sector } from 'recharts'; -import { Layer } from '../../../src/container/Layer'; import { mount, render } from 'enzyme'; +import { render as testingLibraryRender, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import sinon from 'sinon'; +import { Layer } from '../../../src/container/Layer'; describe('', () => { const sectors = [ { - cx: 250, cy: 250, innerRadius: 50, outerRadius: 100, startAngle: 0, - endAngle: 72, name: 'A', value: 40, + cx: 250, + cy: 250, + innerRadius: 50, + outerRadius: 100, + startAngle: 0, + endAngle: 72, + name: 'A', + value: 40, }, - { cx: 250, cy: 250, innerRadius: 50, outerRadius: 100, startAngle: 72, endAngle: 144}, - { cx: 250, cy: 250, innerRadius: 50, outerRadius: 100, startAngle: 144, endAngle: 216}, - { cx: 250, cy: 250, innerRadius: 50, outerRadius: 100, startAngle: 216, endAngle: 288}, - { cx: 250, cy: 250, innerRadius: 50, outerRadius: 100, startAngle: 288, endAngle: 360}, + { cx: 250, cy: 250, innerRadius: 50, outerRadius: 100, startAngle: 72, endAngle: 144 }, + { cx: 250, cy: 250, innerRadius: 50, outerRadius: 100, startAngle: 144, endAngle: 216 }, + { cx: 250, cy: 250, innerRadius: 50, outerRadius: 100, startAngle: 216, endAngle: 288 }, + { cx: 250, cy: 250, innerRadius: 50, outerRadius: 100, startAngle: 288, endAngle: 360 }, ]; it('Render 5 sectors in a simple Pie', () => { const wrapper = render( - - - ); - - expect(wrapper.find('.recharts-pie-sector').length).to.equal(sectors.length); - }); - - it('Render customized active sector when activeShape is set to be an element', () => { - const ActiveShape = props => - - ; - const wrapper = render( - - } - cx={250} - cy={250} - innerRadius={0} - outerRadius={200} - sectors={sectors} - /> - - ); - - expect(wrapper.find('.customized-active-shape').length).to.equal(1); - }); - - it('Render customized active sector when activeShape is set to be a function', () => { - const renderActiveShape = props => - - ; - const wrapper = render( - - - - ); - - expect(wrapper.find('.customized-active-shape').length).to.equal(1); - }); - - it('Render customized active sector when activeShape is set to be an object', () => { - const wrapper = render( - - - - ); - - expect(wrapper.find('.customized-active-shape').length).to.equal(0); - }); - - it('Render customized active sector when inactiveShape is set to be an element', () => { - const ActiveShape = props => ; - const InactiveShape = props => ; - - const wrapper = render( - - } - inactiveShape={} - cx={250} - cy={250} - innerRadius={0} - outerRadius={200} - sectors={sectors} - /> + , ); - expect(wrapper.find('.customized-inactive-shape').length).to.equal(4); - }); - it('Render customized inactive sector when inactiveShape is set to be a function', () => { - const renderActiveShape = props => ; - const renderInactiveShape = props => ; - const wrapper = render( - - - , - ); - expect(wrapper.find('.customized-inactive-shape').length).to.equal(4); - }); - - it('Render customized inactive sector when inactiveShape is set to be an object', () => { - const wrapper = render( - - - , - ); - - expect(wrapper.find('.customized-inactive-shape').length).to.equal(0); - }); - - it('should not render customized inactive sectors if there is no active index', () => { - const renderActiveShape = props => ; - const renderInactiveShape = props => ; - const wrapper = render( - - - , - ); - expect(wrapper.find('.customized-inactive-shape').length).to.equal(0); - }); - - it('Support multiple active sectors', () => { - const ActiveShape = props => - - ; - const wrapper = render( - - } - cx={250} - cy={250} - innerRadius={0} - outerRadius={200} - sectors={sectors} - /> - , - ); - - expect(wrapper.find('.customized-active-shape').length).to.equal(2); - }); - - it('Render customized label when label is set to be a react element', () => { - const Label = (props) => { - const { x, y } = props; - return test; - }; - const wrapper = render( - - } - innerRadius={0} - outerRadius={200} - sectors={sectors} - /> - , - ); - - expect(wrapper.find('.customized-label').length).to.equal(sectors.length); - }); - - it('Render customized label when label is set to be a function that returns the label text', () => { - const Label = (props) => { - const { name, value } = props; - return `${name}: ${value}`; - }; - const wrapper = render( - - - , - ); - - setTimeout(() => { - expect(wrapper.find('.recharts-pie-label-text').length).to.equal(sectors.length); - expect(wrapper.find('.recharts-pie-label-text').first().text()).to.equal('A: 40'); - }, 1000); - }); - - it('Render customized label when label is set to be a react element', () => { - const renderLabel = (props) => { - const { x, y } = props; - return test; - }; - const wrapper = render( - - - , - ); - - expect(wrapper.find('.customized-label').length).to.equal(sectors.length); - }); - - it('Render customized label line when labelLine is set to be a react element', () => { - const LabelLine = (props) => { - const { points } = props; - - return ; - }; - const wrapper = render( - - } - innerRadius={0} - outerRadius={200} - sectors={sectors} - /> - , - ); - - expect(wrapper.find('.customized-label-line').length).to.equal(sectors.length); - }); - - it('Render customized label line when labelLine is set to be a function', () => { - const renderLabelLine = (props) => { - const { points } = props; - - return ; - }; - const wrapper = render( - - - , - ); - - expect(wrapper.find('.customized-label-line').length).to.equal(sectors.length); - }); - - it('Don\'t render any sector when data is empty', () => { - const wrapper = render( - - - - ); - - expect(wrapper.find('.recharts-pie').length).to.equal(0); + expect(wrapper.find('.recharts-pie-sector').length).to.equal(sectors.length); }); - it('Pie event handler', () => { - const onMouseEnter = sinon.spy(); - const onMouseLeave = sinon.spy(); - const onClick = sinon.spy(); - const wrapper = mount( - - - , - ); - const se = wrapper.find(Layer).at(3); - - se.simulate('mouseEnter'); - expect(onMouseEnter.calledOnce).to.equal(true); - se.simulate('mouseLeave'); - expect(onMouseLeave.calledOnce).to.equal(true); - se.simulate('click'); - expect(onClick.calledOnce).to.equal(true); - }); -}); + it('Render customized active sector when activeShape is set to be an element', () => { + const ActiveShape = props => + + ; + const wrapper = render( + + } + cx={250} + cy={250} + innerRadius={0} + outerRadius={200} + sectors={sectors} + /> + , + ); + + expect(wrapper.find('.customized-active-shape').length).to.equal(1); + }); + + it('Render customized active sector when activeShape is set to be a function', () => { + const renderActiveShape = props => ; + const wrapper = render( + + + , + ); + + expect(wrapper.find('.customized-active-shape').length).to.equal(1); + }); + + it('Render customized active sector when activeShape is set to be an object', () => { + const wrapper = render( + + + , + ); + + expect(wrapper.find('.customized-active-shape').length).to.equal(0); + }); + + it('Render customized active sector when inactiveShape is set to be an element', () => { + const ActiveShape = props => ; + const InactiveShape = props => ; + + const wrapper = render( + + } + inactiveShape={} + cx={250} + cy={250} + innerRadius={0} + outerRadius={200} + sectors={sectors} + /> + , + ); + expect(wrapper.find('.customized-inactive-shape').length).to.equal(4); + }); + + it('Render customized inactive sector when inactiveShape is set to be a function', () => { + const renderActiveShape = props => ; + const renderInactiveShape = props => ; + const wrapper = render( + + + , + ); + expect(wrapper.find('.customized-inactive-shape').length).to.equal(4); + }); + + it('Render customized inactive sector when inactiveShape is set to be an object', () => { + const wrapper = render( + + + , + ); + + expect(wrapper.find('.customized-inactive-shape').length).to.equal(0); + }); + + it('should not render customized inactive sectors if there is no active index', () => { + const renderActiveShape = props => ; + const renderInactiveShape = props => ; + const wrapper = render( + + + , + ); + expect(wrapper.find('.customized-inactive-shape').length).to.equal(0); + }); + + it('Support multiple active sectors', () => { + const ActiveShape = props => ; + const wrapper = render( + + } + cx={250} + cy={250} + innerRadius={0} + outerRadius={200} + sectors={sectors} + /> + , + ); + + expect(wrapper.find('.customized-active-shape').length).to.equal(2); + }); + + it('Render customized label when label is set to be a react element', () => { + const Label = props => { + const { x, y } = props; + return ( + + test + + ); + }; + const wrapper = render( + + } + innerRadius={0} + outerRadius={200} + sectors={sectors} + /> + , + ); + + expect(wrapper.find('.customized-label').length).to.equal(sectors.length); + }); + + it('Render customized label when label is set to be a function that returns the label text', () => { + const Label = props => { + const { name, value } = props; + return `${name}: ${value}`; + }; + const wrapper = render( + + + , + ); + + setTimeout(() => { + expect(wrapper.find('.recharts-pie-label-text').length).to.equal(sectors.length); + expect(wrapper.find('.recharts-pie-label-text').first().text()).to.equal('A: 40'); + }, 1000); + }); + + it('Render customized label when label is set to be a react element', () => { + const renderLabel = props => { + const { x, y } = props; + return ( + + test + + ); + }; + const wrapper = render( + + + , + ); + + expect(wrapper.find('.customized-label').length).to.equal(sectors.length); + }); + + it('Render customized label line when labelLine is set to be a react element', () => { + const LabelLine = props => { + const { points } = props; + + return ( + + ); + }; + const wrapper = render( + + } + innerRadius={0} + outerRadius={200} + sectors={sectors} + /> + , + ); + + expect(wrapper.find('.customized-label-line').length).to.equal(sectors.length); + }); + + it('Render customized label line when labelLine is set to be a function', () => { + const renderLabelLine = props => { + const { points } = props; + + return ( + + ); + }; + const wrapper = render( + + + , + ); + + expect(wrapper.find('.customized-label-line').length).to.equal(sectors.length); + }); + + it("Don't render any sector when data is empty", () => { + const wrapper = render( + + + , + ); + + expect(wrapper.find('.recharts-pie').length).to.equal(0); + }); + + it('Pie event handler', () => { + const onMouseEnter = sinon.spy(); + const onMouseLeave = sinon.spy(); + const onClick = sinon.spy(); + const wrapper = mount( + + + , + ); + const se = wrapper.find(Layer).at(3); + + se.simulate('mouseEnter'); + expect(onMouseEnter.calledOnce).to.equal(true); + se.simulate('mouseLeave'); + expect(onMouseLeave.calledOnce).to.equal(true); + se.simulate('click'); + expect(onClick.calledOnce).to.equal(true); + }); + + it('Handles keyboard interaction: Tab can focus in and out of the pie chart', async () => { + const timeout = 2000; + const { container } = testingLibraryRender( + // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex +
+ + + +
, + ); + const pie = container.getElementsByClassName('recharts-pie')[0]; + const pieContainer = document.getElementsByClassName('container')[0]; + + pieContainer.focus(); + await waitFor( + () => { + expect(document.activeElement).equals(pieContainer); + }, + { timeout }, + ); + + // Testing that pressing tab goes into pie chart + userEvent.tab(); + await waitFor( + () => { + expect(document.activeElement).equals(pie); + }, + { timeout }, + ); + + // Testing that pressing tab goes out of pie chart + userEvent.tab(); + await waitFor( + () => { + expect(document.activeElement).equals(document.body); + }, + { timeout }, + ); + }); + + it('Handles keyboard interaction: arrow keys can move focus into sectors', async () => { + const timeout = 2000; + const { container } = testingLibraryRender( + // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex +
+ + + +
, + ); + const pie = container.getElementsByClassName('recharts-pie')[0]; + pie.focus(); + await waitFor( + () => { + expect(document.activeElement.classList.contains('recharts-pie-sector')).to.equal(false); + }, + { timeout }, + ); + + userEvent.keyboard('{ArrowRight}'); + + await waitFor( + () => { + expect(document.activeElement.classList.contains('recharts-pie-sector')).to.equal(true); + }, + { timeout }, + ); + }); + }); \ No newline at end of file