From d47e7cd38c490903b1d62caf2e2c3951e56cd118 Mon Sep 17 00:00:00 2001 From: saghan Date: Thu, 28 Jul 2022 09:55:57 -0700 Subject: [PATCH 01/11] added keyboard navigation --- src/polar/Pie.tsx | 62 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/src/polar/Pie.tsx b/src/polar/Pie.tsx index bc267d4339..d28226e1e5 100644 --- a/src/polar/Pie.tsx +++ b/src/polar/Pie.tsx @@ -120,11 +120,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 = { @@ -293,6 +298,7 @@ export class Pie extends PureComponent { isAnimationFinished: !props.isAnimationActive, prevIsAnimationActive: props.isAnimationActive, prevAnimationId: props.animationId, + sectorToFocus: 0, }; } @@ -462,10 +468,10 @@ export class Pie extends PureComponent { return option(props); } if (_.isPlainObject(option)) { - return ; + return ; } - return ; + return ; } renderSectorsStatically(sectors: PieSectorDataItem[]) { @@ -480,6 +486,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 @@ -546,6 +558,38 @@ export class Pie extends PureComponent { ); } + attachKeyboardHandlers(pieRef: HTMLElement) { + 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; @@ -556,6 +600,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; @@ -575,7 +625,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)} From 59573962226f0ccd0090d2ae9b6415dd39931433 Mon Sep 17 00:00:00 2001 From: saghan Date: Thu, 28 Jul 2022 10:34:29 -0700 Subject: [PATCH 02/11] made focus state optional --- src/polar/Pie.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polar/Pie.tsx b/src/polar/Pie.tsx index d28226e1e5..5b7da34f4f 100644 --- a/src/polar/Pie.tsx +++ b/src/polar/Pie.tsx @@ -120,7 +120,7 @@ interface State { prevSectors?: PieSectorDataItem[]; curSectors?: PieSectorDataItem[]; prevAnimationId?: number; - sectorToFocus: number; + sectorToFocus?: number; } export type Props = PresentationAttributesAdaptChildEvent & PieProps; From 81ae6922472bd3e6e0a7703a5895026fecd02c22 Mon Sep 17 00:00:00 2001 From: saghan Date: Sun, 31 Jul 2022 16:52:59 -0700 Subject: [PATCH 03/11] added test --- package-lock.json | 570 ++++++++++++++++++++++++++++++++++++ package.json | 2 + src/container/Layer.tsx | 6 +- test/specs/polar/PieSpec.js | 188 ++++++++---- 4 files changed, 714 insertions(+), 52 deletions(-) diff --git a/package-lock.json b/package-lock.json index 02766d72a8..5857e65fde 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,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/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", @@ -1636,6 +1638,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", @@ -1741,6 +1829,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", @@ -1851,6 +2064,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", @@ -1943,6 +2180,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", @@ -4486,6 +4738,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", @@ -8408,6 +8666,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", @@ -9883,6 +10150,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", @@ -15246,6 +15567,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", @@ -15339,6 +15724,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", @@ -15449,6 +15924,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", @@ -15541,6 +16040,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", @@ -17529,6 +18043,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", @@ -20573,6 +21093,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", @@ -21701,6 +22227,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 a86d46e8b2..f86201cb98 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,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/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", diff --git a/src/container/Layer.tsx b/src/container/Layer.tsx index ebed65d613..6a3228a9dc 100644 --- a/src/container/Layer.tsx +++ b/src/container/Layer.tsx @@ -12,13 +12,13 @@ interface LayerProps { export type Props = SVGProps & LayerProps; -export function Layer(props: Props) { +export const Layer = React.forwardRef((props: Props, ref: any) => { const { children, className, ...others } = props; const layerClass = classNames('recharts-layer', className); return ( - + {children} ); -} +}); diff --git a/test/specs/polar/PieSpec.js b/test/specs/polar/PieSpec.js index 984548cfab..d3510a07c9 100644 --- a/test/specs/polar/PieSpec.js +++ b/test/specs/polar/PieSpec.js @@ -1,43 +1,42 @@ 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 { fireEvent, 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 a element', () => { - const ActiveShape = props => - - ; + const ActiveShape = props => ; const wrapper = render( ', () => { 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 renderActiveShape = props => ; const wrapper = render( ', () => { outerRadius={200} sectors={sectors} /> - + , ); expect(wrapper.find('.customized-active-shape').length).to.equal(1); @@ -91,16 +88,14 @@ describe('', () => { outerRadius={200} sectors={sectors} /> - + , ); expect(wrapper.find('.customized-active-shape').length).to.equal(0); }); it('Support multiple active sectors', () => { - const ActiveShape = props => - - ; + const ActiveShape = props => ; const wrapper = render( ', () => { 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 Label = props => { const { x, y } = props; - return test; + return ( + + test + + ); }; const wrapper = render( @@ -135,14 +134,14 @@ describe('', () => { 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 Label = props => { const { name, value } = props; return `${name}: ${value}`; }; @@ -157,7 +156,7 @@ describe('', () => { outerRadius={200} sectors={sectors} /> - + , ); setTimeout(() => { @@ -167,9 +166,13 @@ describe('', () => { }); it('Render customized label when label is set to be a react element', () => { - const renderLabel = (props) => { + const renderLabel = props => { const { x, y } = props; - return test; + return ( + + test + + ); }; const wrapper = render( @@ -182,17 +185,19 @@ describe('', () => { outerRadius={200} sectors={sectors} /> - + , ); 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 LabelLine = props => { const { points } = props; - return ; + return ( + + ); }; const wrapper = render( @@ -206,17 +211,19 @@ describe('', () => { 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 renderLabelLine = props => { const { points } = props; - return ; + return ( + + ); }; const wrapper = render( @@ -230,19 +237,17 @@ describe('', () => { outerRadius={200} sectors={sectors} /> - + , ); expect(wrapper.find('.customized-label-line').length).to.equal(sectors.length); }); - it('Don\'t render any sector when data is empty', () => { + it("Don't render any sector when data is empty", () => { const wrapper = render( - - + + , ); expect(wrapper.find('.recharts-pie').length).to.equal(0); @@ -265,7 +270,7 @@ describe('', () => { onMouseLeave={onMouseLeave} onClick={onClick} /> - + , ); const se = wrapper.find(Layer).at(3); @@ -276,4 +281,89 @@ describe('', () => { 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( +
+ + + +
, + ); + 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); + it('Handles keyboard interaction: Tab can focus in and out of the pie chart', async () => { + const timeout = 2000; + const { container } = testingLibraryRender( +
+ + + +
, + ); + 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 }, + ); + }); + }, + { timeout }, + ); + }); }); From 116e731a32b9112dbf60b00a9fada16550705423 Mon Sep 17 00:00:00 2001 From: saghan Date: Mon, 1 Aug 2022 10:46:41 -0700 Subject: [PATCH 04/11] arrow navigation test added --- test/specs/polar/PieSpec.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/specs/polar/PieSpec.js b/test/specs/polar/PieSpec.js index d3510a07c9..4ec56e9906 100644 --- a/test/specs/polar/PieSpec.js +++ b/test/specs/polar/PieSpec.js @@ -366,4 +366,32 @@ describe('', () => { { timeout }, ); }); + + it.only('Handles keyboard interaction: left/right arrow keys can move focus within sectors', async () => { + const timeout = 2000; + const { container } = testingLibraryRender( +
+ + + +
, + ); + 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 }, + ); + }); }); From 6020d8cc1f23dad55fcf50045cb3f1b9fb971439 Mon Sep 17 00:00:00 2001 From: saghan Date: Mon, 1 Aug 2022 11:55:59 -0700 Subject: [PATCH 05/11] rename test description --- test/specs/polar/PieSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/specs/polar/PieSpec.js b/test/specs/polar/PieSpec.js index 4ec56e9906..bd6d8535a9 100644 --- a/test/specs/polar/PieSpec.js +++ b/test/specs/polar/PieSpec.js @@ -367,7 +367,7 @@ describe('', () => { ); }); - it.only('Handles keyboard interaction: left/right arrow keys can move focus within sectors', async () => { + it.only('Handles keyboard interaction: arrow keys can move focus into sectors', async () => { const timeout = 2000; const { container } = testingLibraryRender(
From a4be37ea8c1f6c425b88ffedc26faa8f33d7c565 Mon Sep 17 00:00:00 2001 From: saghan Date: Mon, 1 Aug 2022 12:10:18 -0700 Subject: [PATCH 06/11] remove unnecessary import --- test/specs/polar/PieSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/specs/polar/PieSpec.js b/test/specs/polar/PieSpec.js index bd6d8535a9..66a3ea4ac2 100644 --- a/test/specs/polar/PieSpec.js +++ b/test/specs/polar/PieSpec.js @@ -2,7 +2,7 @@ import React from 'react'; import { expect } from 'chai'; import { Surface, Pie, Sector } from 'recharts'; import { mount, render } from 'enzyme'; -import { fireEvent, render as testingLibraryRender, waitFor } from '@testing-library/react'; +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'; From b32b5227b9b4a6e90a782597755ec1ab619ca675 Mon Sep 17 00:00:00 2001 From: saghan Date: Mon, 1 Aug 2022 12:29:36 -0700 Subject: [PATCH 07/11] removed only from test --- test/specs/polar/PieSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/specs/polar/PieSpec.js b/test/specs/polar/PieSpec.js index 66a3ea4ac2..43c1b0e469 100644 --- a/test/specs/polar/PieSpec.js +++ b/test/specs/polar/PieSpec.js @@ -367,7 +367,7 @@ describe('', () => { ); }); - it.only('Handles keyboard interaction: arrow keys can move focus into sectors', async () => { + it('Handles keyboard interaction: arrow keys can move focus into sectors', async () => { const timeout = 2000; const { container } = testingLibraryRender(
From eee06efb94e4faadfde4751cd88d4902394a6150 Mon Sep 17 00:00:00 2001 From: saghan Date: Mon, 1 Aug 2022 17:08:54 -0700 Subject: [PATCH 08/11] fixed eslint and copy-paste error --- src/polar/Pie.tsx | 1 + test/specs/polar/PieSpec.js | 48 ++----------------------------------- 2 files changed, 3 insertions(+), 46 deletions(-) diff --git a/src/polar/Pie.tsx b/src/polar/Pie.tsx index 5b7da34f4f..698d6ac718 100644 --- a/src/polar/Pie.tsx +++ b/src/polar/Pie.tsx @@ -559,6 +559,7 @@ 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) { diff --git a/test/specs/polar/PieSpec.js b/test/specs/polar/PieSpec.js index 43c1b0e469..422a8c91a4 100644 --- a/test/specs/polar/PieSpec.js +++ b/test/specs/polar/PieSpec.js @@ -285,6 +285,7 @@ describe('', () => { 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
@@ -316,52 +317,6 @@ describe('', () => { await waitFor( () => { expect(document.activeElement).equals(document.body); - it('Handles keyboard interaction: Tab can focus in and out of the pie chart', async () => { - const timeout = 2000; - const { container } = testingLibraryRender( -
- - - -
, - ); - 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 }, - ); - }); }, { timeout }, ); @@ -370,6 +325,7 @@ describe('', () => { 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
From 2cbc208a3998c3fe16811d90c72a4f4d65a4e9ab Mon Sep 17 00:00:00 2001 From: Saghan Mudbhari Date: Thu, 22 Sep 2022 03:33:29 -0700 Subject: [PATCH 09/11] Trigger Build From c6e335d39369a70fb9063cd1045660f9edc2cdef Mon Sep 17 00:00:00 2001 From: Saghan Mudbhari Date: Fri, 30 Sep 2022 21:43:37 -0700 Subject: [PATCH 10/11] added jdoc --- src/cartesian/CartesianAxis.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cartesian/CartesianAxis.tsx b/src/cartesian/CartesianAxis.tsx index caca6cf115..36b6d03265 100644 --- a/src/cartesian/CartesianAxis.tsx +++ b/src/cartesian/CartesianAxis.tsx @@ -450,6 +450,8 @@ export class CartesianAxis extends Component { /** * render the ticks * @param {Array} ticks The ticks to actually render (overrides what was passed in props) + * @param {String} fontSize The fontSize to use when calculating size of ticks + * @param {String} letterSpacing The letterSpacing to use when calculating size of ticks * @return {ReactComponent} renderedTicks */ renderTicks(ticks: CartesianTickItem[], fontSize: string, letterSpacing: string) { From 568a4b96c1483eca36394cdd68f058fd6fd75828 Mon Sep 17 00:00:00 2001 From: Saghan Mudbhari Date: Fri, 30 Sep 2022 23:44:30 -0700 Subject: [PATCH 11/11] copypaste error fixed --- test/specs/polar/PieSpec.js | 734 ++++++++++++++++++------------------ 1 file changed, 366 insertions(+), 368 deletions(-) diff --git a/test/specs/polar/PieSpec.js b/test/specs/polar/PieSpec.js index 0e68f5c38b..a59d36ded1 100644 --- a/test/specs/polar/PieSpec.js +++ b/test/specs/polar/PieSpec.js @@ -35,406 +35,404 @@ describe('', () => { expect(wrapper.find('.recharts-pie-sector').length).to.equal(sectors.length); }); - it('Render customized active sector when activeShape is set to be a element', () => { - const ActiveShape = props => ; - 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( - - - , - ); + 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); - }); + 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( - - - , - ); + 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(0); - }); + expect(wrapper.find('.customized-active-shape').length).to.equal(1); + }); - it('Render customized active sector when inactiveShape is set to be an element', () => { - const ActiveShape = props => ; - const InactiveShape = props => ; + it('Render customized active sector when activeShape is set to be an object', () => { + const wrapper = render( + + + , + ); - const wrapper = render( - - } - inactiveShape={} - cx={250} - cy={250} - innerRadius={0} - outerRadius={200} - sectors={sectors} - /> - , - ); - expect(wrapper.find('.customized-inactive-shape').length).to.equal(4); - }); + expect(wrapper.find('.customized-active-shape').length).to.equal(0); + }); - 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 active sector when inactiveShape is set to be an element', () => { + const ActiveShape = props => ; + const InactiveShape = props => ; - it('Render customized inactive sector when inactiveShape is set to be an object', () => { - const wrapper = render( - - - , - ); + const wrapper = render( + + } + inactiveShape={} + cx={250} + cy={250} + innerRadius={0} + outerRadius={200} + sectors={sectors} + /> + , + ); + expect(wrapper.find('.customized-inactive-shape').length).to.equal(4); + }); - expect(wrapper.find('.customized-inactive-shape').length).to.equal(0); - }); + 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('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('Render customized inactive sector when inactiveShape is set to be an object', () => { + const wrapper = render( + + + , + ); - 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-inactive-shape').length).to.equal(0); + }); - expect(wrapper.find('.customized-active-shape').length).to.equal(2); - }); + 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('Render customized label when label is set to be a react element', () => { - const Label = props => { - const { x, y } = props; - return ( - - test - + it('Support multiple active sectors', () => { + const ActiveShape = props => ; + const wrapper = render( + + } + cx={250} + cy={250} + innerRadius={0} + outerRadius={200} + sectors={sectors} + /> + , ); - }; - const wrapper = render( - - } - innerRadius={0} - outerRadius={200} - sectors={sectors} - /> - , - ); - expect(wrapper.find('.customized-label').length).to.equal(sectors.length); - }); + 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} + /> + , + ); - 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( - - - , - ); + expect(wrapper.find('.customized-label').length).to.equal(sectors.length); + }); - 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 function that returns the label text', () => { + const Label = props => { + const { name, value } = props; + return `${name}: ${value}`; + }; + const wrapper = render( + + + , + ); - it('Render customized label when label is set to be a react element', () => { - const renderLabel = props => { - const { x, y } = props; - return ( - - test - + 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( + + + , ); - }; - const wrapper = render( - - - , - ); - expect(wrapper.find('.customized-label').length).to.equal(sectors.length); - }); + 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; + it('Render customized label line when labelLine is set to be a react element', () => { + const LabelLine = props => { + const { points } = props; - return ( - + return ( + + ); + }; + const wrapper = render( + + } + innerRadius={0} + outerRadius={200} + sectors={sectors} + /> + , ); - }; - const wrapper = render( - - } - innerRadius={0} - outerRadius={200} - sectors={sectors} - /> - , - ); - expect(wrapper.find('.customized-label-line').length).to.equal(sectors.length); - }); + 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; + it('Render customized label line when labelLine is set to be a function', () => { + const renderLabelLine = props => { + const { points } = props; - return ( - + return ( + + ); + }; + const wrapper = render( + + + , ); - }; - 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('.customized-label-line').length).to.equal(sectors.length); + }); - expect(wrapper.find('.recharts-pie').length).to.equal(0); - }); + it("Don't render any sector when data is empty", () => { + const wrapper = render( + + + , + ); - 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); - }); + expect(wrapper.find('.recharts-pie').length).to.equal(0); + }); - 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 -
+ it('Pie event handler', () => { + const onMouseEnter = sinon.spy(); + const onMouseLeave = sinon.spy(); + const onClick = sinon.spy(); + const wrapper = mount( - - -
, - ); - 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 }, - ); + +
, + ); + 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 out of pie chart - userEvent.tab(); - await waitFor( - () => { - expect(document.activeElement).equals(document.body); - }, - { timeout }, - ); - }); + // Testing that pressing tab goes into pie chart + userEvent.tab(); + await waitFor( + () => { + expect(document.activeElement).equals(pie); + }, + { 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 }, - ); + // 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}'); + userEvent.keyboard('{ArrowRight}'); - await waitFor( - () => { - expect(document.activeElement.classList.contains('recharts-pie-sector')).to.equal(true); - }, - { timeout }, - ); - }); -}); + await waitFor( + () => { + expect(document.activeElement.classList.contains('recharts-pie-sector')).to.equal(true); + }, + { timeout }, + ); + }); + }); \ No newline at end of file