Write integration tests (#719)
* Scaffold a simple test case for debugging * Set up Jest environment that works with React - Install and set up react-testing-library - "Unignore" roughjs and browser-nativejs transformations - Separate App component from ReactDOM * Write first passing test - Mock canvas - Remove App file and mount/unmount ReactDOM on import * Add tests for drag create behavior * Fix comments in dragCreate * Pin jest-mock-canvas dependency * Remove dependency range for testing library * Add tests for multi point mode and selection element * Fix all tests due to decrease in updates to canvas when changing tools * Disable state updates if component is unmounted - Remove all event listeners - Disable storing scene in state if component is unmounted * Add tests for move and element selection * Merge branch 'master' into add-integration-tests * Add tests for resizing rectangle * move unmounted check to syncActionResult method * Use a custom test renderer instead of default testing-library functions * Add custom query for selecting tools * move files around Co-authored-by: David Luzar <luzar.david@gmail.com>
This commit is contained in:
parent
ad4ad238ef
commit
7183234895
268
package-lock.json
generated
268
package-lock.json
generated
@ -1292,6 +1292,12 @@
|
|||||||
"any-observable": "^0.3.0"
|
"any-observable": "^0.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@sheerun/mutationobserver-shim": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-vTCdPp/T/Q3oSqwHmZ5Kpa9oI7iLtGl3RQaA/NyLHikvcrPxACkkKVr/XzkSPJWXHRhKGzVvb0urJsbMlRxi1Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@svgr/babel-plugin-add-jsx-attribute": {
|
"@svgr/babel-plugin-add-jsx-attribute": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz",
|
||||||
@ -1401,6 +1407,189 @@
|
|||||||
"loader-utils": "^1.2.3"
|
"loader-utils": "^1.2.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@testing-library/dom": {
|
||||||
|
"version": "6.12.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-6.12.2.tgz",
|
||||||
|
"integrity": "sha512-KCnvHra5fV+wDxg3wJObGvZFxq7v1DJt829GNFLuRDjKxVNc/B5AdsylNF5PMHFbWMXDsHwM26d2NZcZO9KjbQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.6.2",
|
||||||
|
"@sheerun/mutationobserver-shim": "^0.3.2",
|
||||||
|
"@types/testing-library__dom": "^6.0.0",
|
||||||
|
"aria-query": "3.0.0",
|
||||||
|
"pretty-format": "^24.9.0",
|
||||||
|
"wait-for-expect": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@testing-library/jest-dom": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-7xnmBFcUmmUVAUhFiZ/u3CxFh1e46THAwra4SiiKNCW4By26RedCRwEk0rtleFPZG0wlTSNOKDvJjWYy93dp0w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.8.3",
|
||||||
|
"@types/testing-library__jest-dom": "^5.0.0",
|
||||||
|
"chalk": "^3.0.0",
|
||||||
|
"css": "^2.2.4",
|
||||||
|
"css.escape": "^1.5.1",
|
||||||
|
"jest-diff": "^25.1.0",
|
||||||
|
"jest-matcher-utils": "^25.1.0",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"pretty-format": "^25.1.0",
|
||||||
|
"redent": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@jest/types": {
|
||||||
|
"version": "25.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jest/types/-/types-25.1.0.tgz",
|
||||||
|
"integrity": "sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/istanbul-lib-coverage": "^2.0.0",
|
||||||
|
"@types/istanbul-reports": "^1.1.1",
|
||||||
|
"@types/yargs": "^15.0.0",
|
||||||
|
"chalk": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/yargs": {
|
||||||
|
"version": "15.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.3.tgz",
|
||||||
|
"integrity": "sha512-XCMQRK6kfpNBixHLyHUsGmXrpEmFFxzMrcnSXFMziHd8CoNJo8l16FkHyQq4x+xbM7E2XL83/O78OD8u+iZTdQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/yargs-parser": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/color-name": "^1.1.1",
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"diff-sequences": {
|
||||||
|
"version": "25.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.1.0.tgz",
|
||||||
|
"integrity": "sha512-nFIfVk5B/NStCsJ+zaPO4vYuLjlzQ6uFvPxzYyHlejNZ/UGa7G/n7peOXVrVNvRuyfstt+mZQYGpjxg9Z6N8Kw==",
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"jest-diff": {
|
||||||
|
"version": "25.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.1.0.tgz",
|
||||||
|
"integrity": "sha512-nepXgajT+h017APJTreSieh4zCqnSHEJ1iT8HDlewu630lSJ4Kjjr9KNzm+kzGwwcpsDE6Snx1GJGzzsefaEHw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"chalk": "^3.0.0",
|
||||||
|
"diff-sequences": "^25.1.0",
|
||||||
|
"jest-get-type": "^25.1.0",
|
||||||
|
"pretty-format": "^25.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jest-get-type": {
|
||||||
|
"version": "25.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.1.0.tgz",
|
||||||
|
"integrity": "sha512-yWkBnT+5tMr8ANB6V+OjmrIJufHtCAqI5ic2H40v+tRqxDmE0PGnIiTyvRWFOMtmVHYpwRqyazDbTnhpjsGvLw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"jest-matcher-utils": {
|
||||||
|
"version": "25.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-25.1.0.tgz",
|
||||||
|
"integrity": "sha512-KGOAFcSFbclXIFE7bS4C53iYobKI20ZWleAdAFun4W1Wz1Kkej8Ng6RRbhL8leaEvIOjGXhGf/a1JjO8bkxIWQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"chalk": "^3.0.0",
|
||||||
|
"jest-diff": "^25.1.0",
|
||||||
|
"jest-get-type": "^25.1.0",
|
||||||
|
"pretty-format": "^25.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pretty-format": {
|
||||||
|
"version": "25.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.1.0.tgz",
|
||||||
|
"integrity": "sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@jest/types": "^25.1.0",
|
||||||
|
"ansi-regex": "^5.0.0",
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"react-is": "^16.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redent": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"indent-string": "^4.0.0",
|
||||||
|
"strip-indent": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-indent": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"min-indent": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@testing-library/react": {
|
||||||
|
"version": "9.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-9.4.0.tgz",
|
||||||
|
"integrity": "sha512-XdhDWkI4GktUPsz0AYyeQ8M9qS/JFie06kcSnUVcpgOwFjAu9vhwR83qBl+lw9yZWkbECjL8Hd+n5hH6C0oWqg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.7.6",
|
||||||
|
"@testing-library/dom": "^6.11.0",
|
||||||
|
"@types/testing-library__react": "^9.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/babel__core": {
|
"@types/babel__core": {
|
||||||
"version": "7.1.3",
|
"version": "7.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz",
|
||||||
@ -1668,6 +1857,34 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||||
"integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw=="
|
"integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw=="
|
||||||
},
|
},
|
||||||
|
"@types/testing-library__dom": {
|
||||||
|
"version": "6.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/testing-library__dom/-/testing-library__dom-6.12.0.tgz",
|
||||||
|
"integrity": "sha512-PQ/gzABzc53T68RldZ/sJHKCihtP9ofU8XIgOk+H7tlfoCRdg9mqICio5Fo8j3Z8wo+pOfuDsuPprWsn3YtVmA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"pretty-format": "^24.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/testing-library__jest-dom": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-GiPXQBVF9O4DG9cssD2d266vozBJvC5Tnv6aeH5ujgYJgys1DYm9AFCz7YC+STR5ksGxq3zCt+yP8T1wbk2DFg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/jest": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/testing-library__react": {
|
||||||
|
"version": "9.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/testing-library__react/-/testing-library__react-9.1.2.tgz",
|
||||||
|
"integrity": "sha512-CYaMqrswQ+cJACy268jsLAw355DZtPZGt3Jwmmotlcu8O/tkoXBI6AeZ84oZBJsIsesozPKzWzmv/0TIU+1E9Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"@types/testing-library__dom": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
"version": "13.0.8",
|
"version": "13.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz",
|
||||||
@ -3863,6 +4080,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz",
|
||||||
"integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw=="
|
"integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw=="
|
||||||
},
|
},
|
||||||
|
"css.escape": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
|
||||||
|
"integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"cssdb": {
|
"cssdb": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz",
|
||||||
@ -3873,6 +4096,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
|
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
|
||||||
},
|
},
|
||||||
|
"cssfontparser": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cssfontparser/-/cssfontparser-1.2.1.tgz",
|
||||||
|
"integrity": "sha1-9AIvyPlwDGgCnVQghK+69CWj8+M=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"cssnano": {
|
"cssnano": {
|
||||||
"version": "4.1.10",
|
"version": "4.1.10",
|
||||||
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz",
|
||||||
@ -7154,6 +7383,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jest-canvas-mock": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-canvas-mock/-/jest-canvas-mock-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-DcJdchb7eWFZkt6pvyceWWnu3lsp5QWbUeXiKgEMhwB3sMm5qHM1GQhDajvJgBeiYpgKcojbzZ53d/nz6tXvJw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"cssfontparser": "^1.2.1",
|
||||||
|
"parse-color": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"jest-changed-files": {
|
"jest-changed-files": {
|
||||||
"version": "24.9.0",
|
"version": "24.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz",
|
||||||
@ -9390,6 +9629,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
|
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
|
||||||
},
|
},
|
||||||
|
"min-indent": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"mini-css-extract-plugin": {
|
"mini-css-extract-plugin": {
|
||||||
"version": "0.9.0",
|
"version": "0.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz",
|
||||||
@ -10359,6 +10604,23 @@
|
|||||||
"safe-buffer": "^5.1.1"
|
"safe-buffer": "^5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"parse-color": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-e3SLlag/A/FqlPU15S1/PZRlhhk=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"color-convert": "~0.5.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": {
|
||||||
|
"version": "0.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
|
||||||
|
"integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"parse-json": {
|
"parse-json": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||||
@ -14952,6 +15214,12 @@
|
|||||||
"xml-name-validator": "^3.0.0"
|
"xml-name-validator": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"wait-for-expect": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-3Ha7lu+zshEG/CeHdcpmQsZnnZpPj/UsG3DuKO8FskjuDbkx3jE3845H+CuwZjA2YWYDfKMU2KhnCaXMLd3wVw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"walker": {
|
"walker": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
},
|
},
|
||||||
"description": "",
|
"description": "",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@testing-library/jest-dom": "5.1.1",
|
||||||
|
"@testing-library/react": "9.4.0",
|
||||||
"@types/jest": "25.1.2",
|
"@types/jest": "25.1.2",
|
||||||
"@types/nanoid": "2.1.0",
|
"@types/nanoid": "2.1.0",
|
||||||
"@types/react": "16.9.19",
|
"@types/react": "16.9.19",
|
||||||
@ -24,12 +26,18 @@
|
|||||||
"eslint-config-prettier": "6.10.0",
|
"eslint-config-prettier": "6.10.0",
|
||||||
"eslint-plugin-prettier": "3.1.2",
|
"eslint-plugin-prettier": "3.1.2",
|
||||||
"husky": "4.2.1",
|
"husky": "4.2.1",
|
||||||
|
"jest-canvas-mock": "2.2.0",
|
||||||
"lint-staged": "10.0.7",
|
"lint-staged": "10.0.7",
|
||||||
"node-sass": "4.13.1",
|
"node-sass": "4.13.1",
|
||||||
"prettier": "1.19.1",
|
"prettier": "1.19.1",
|
||||||
"rewire": "4.0.1",
|
"rewire": "4.0.1",
|
||||||
"typescript": "3.7.5"
|
"typescript": "3.7.5"
|
||||||
},
|
},
|
||||||
|
"jest": {
|
||||||
|
"transformIgnorePatterns": [
|
||||||
|
"node_modules/(?!(roughjs|browser-nativefs)/)"
|
||||||
|
]
|
||||||
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
"prettier",
|
"prettier",
|
||||||
|
@ -475,6 +475,9 @@ export class App extends React.Component<any, AppState> {
|
|||||||
res: ActionResult,
|
res: ActionResult,
|
||||||
commitToHistory: boolean = true,
|
commitToHistory: boolean = true,
|
||||||
) => {
|
) => {
|
||||||
|
if (this.unmounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (res.elements) {
|
if (res.elements) {
|
||||||
elements = res.elements;
|
elements = res.elements;
|
||||||
if (commitToHistory) {
|
if (commitToHistory) {
|
||||||
@ -515,6 +518,11 @@ export class App extends React.Component<any, AppState> {
|
|||||||
this.saveDebounced.flush();
|
this.saveDebounced.flush();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private disableEvent: EventHandlerNonNull = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
private unmounted = false;
|
||||||
public async componentDidMount() {
|
public async componentDidMount() {
|
||||||
document.addEventListener("copy", this.onCopy);
|
document.addEventListener("copy", this.onCopy);
|
||||||
document.addEventListener("paste", this.pasteFromClipboard);
|
document.addEventListener("paste", this.pasteFromClipboard);
|
||||||
@ -526,28 +534,32 @@ export class App extends React.Component<any, AppState> {
|
|||||||
window.addEventListener("resize", this.onResize, false);
|
window.addEventListener("resize", this.onResize, false);
|
||||||
window.addEventListener("unload", this.onUnload, false);
|
window.addEventListener("unload", this.onUnload, false);
|
||||||
window.addEventListener("blur", this.onUnload, false);
|
window.addEventListener("blur", this.onUnload, false);
|
||||||
window.addEventListener("dragover", e => e.preventDefault(), false);
|
window.addEventListener("dragover", this.disableEvent, false);
|
||||||
window.addEventListener("drop", e => e.preventDefault(), false);
|
window.addEventListener("drop", this.disableEvent, false);
|
||||||
|
|
||||||
const searchParams = new URLSearchParams(window.location.search);
|
const searchParams = new URLSearchParams(window.location.search);
|
||||||
const id = searchParams.get("id");
|
const id = searchParams.get("id");
|
||||||
|
|
||||||
if (id) {
|
if (id) {
|
||||||
// Backwards compatibility with legacy url format
|
// Backwards compatibility with legacy url format
|
||||||
this.syncActionResult(await loadScene(id));
|
const scene = await loadScene(id);
|
||||||
|
this.syncActionResult(scene);
|
||||||
} else {
|
} else {
|
||||||
const match = window.location.hash.match(
|
const match = window.location.hash.match(
|
||||||
/^#json=([0-9]+),([a-zA-Z0-9_-]+)$/,
|
/^#json=([0-9]+),([a-zA-Z0-9_-]+)$/,
|
||||||
);
|
);
|
||||||
if (match) {
|
if (match) {
|
||||||
this.syncActionResult(await loadScene(match[1], match[2]));
|
const scene = await loadScene(match[1], match[2]);
|
||||||
|
this.syncActionResult(scene);
|
||||||
} else {
|
} else {
|
||||||
this.syncActionResult(await loadScene(null));
|
const scene = await loadScene(null);
|
||||||
|
this.syncActionResult(scene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
|
this.unmounted = true;
|
||||||
document.removeEventListener("copy", this.onCopy);
|
document.removeEventListener("copy", this.onCopy);
|
||||||
document.removeEventListener("paste", this.pasteFromClipboard);
|
document.removeEventListener("paste", this.pasteFromClipboard);
|
||||||
document.removeEventListener("cut", this.onCut);
|
document.removeEventListener("cut", this.onCut);
|
||||||
@ -558,9 +570,12 @@ export class App extends React.Component<any, AppState> {
|
|||||||
this.updateCurrentCursorPosition,
|
this.updateCurrentCursorPosition,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
document.removeEventListener("keyup", this.onKeyUp);
|
||||||
window.removeEventListener("resize", this.onResize, false);
|
window.removeEventListener("resize", this.onResize, false);
|
||||||
window.removeEventListener("unload", this.onUnload, false);
|
window.removeEventListener("unload", this.onUnload, false);
|
||||||
window.removeEventListener("blur", this.onUnload, false);
|
window.removeEventListener("blur", this.onUnload, false);
|
||||||
|
window.removeEventListener("dragover", this.disableEvent, false);
|
||||||
|
window.removeEventListener("drop", this.disableEvent, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public state: AppState = getDefaultAppState();
|
public state: AppState = getDefaultAppState();
|
||||||
|
8
src/setupTests.ts
Normal file
8
src/setupTests.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import "@testing-library/jest-dom";
|
||||||
|
import "jest-canvas-mock";
|
||||||
|
|
||||||
|
// ReactDOM is located inside index.tsx file
|
||||||
|
// as a result, we need a place for it to render into
|
||||||
|
const element = document.createElement("div");
|
||||||
|
element.id = "root";
|
||||||
|
document.body.appendChild(element);
|
277
src/tests/dragCreate.test.tsx
Normal file
277
src/tests/dragCreate.test.tsx
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import { App } from "../index";
|
||||||
|
import * as Renderer from "../renderer/renderScene";
|
||||||
|
import { KEYS } from "../keys";
|
||||||
|
import { render, fireEvent } from "./test-utils";
|
||||||
|
|
||||||
|
// Unmount ReactDOM from root
|
||||||
|
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||||
|
|
||||||
|
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||||
|
beforeEach(() => {
|
||||||
|
localStorage.clear();
|
||||||
|
renderScene.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("add element to the scene when mouse dragging long enough", () => {
|
||||||
|
it("rectangle", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("rectangle");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
// start from (30, 20)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
|
||||||
|
// move to (60,70)
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
|
||||||
|
// finish (position does not matter)
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(4);
|
||||||
|
expect(renderScene.mock.calls[3][1]).toBeNull();
|
||||||
|
const elements = renderScene.mock.calls[3][0];
|
||||||
|
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].type).toEqual("rectangle");
|
||||||
|
expect(elements[0].x).toEqual(30);
|
||||||
|
expect(elements[0].y).toEqual(20);
|
||||||
|
expect(elements[0].width).toEqual(30); // 60 - 30
|
||||||
|
expect(elements[0].height).toEqual(50); // 70 - 20
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ellipse", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("ellipse");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
// start from (30, 20)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
|
||||||
|
// move to (60,70)
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
|
||||||
|
// finish (position does not matter)
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(4);
|
||||||
|
expect(renderScene.mock.calls[3][1]).toBeNull();
|
||||||
|
|
||||||
|
const elements = renderScene.mock.calls[3][0];
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].type).toEqual("ellipse");
|
||||||
|
expect(elements[0].x).toEqual(30);
|
||||||
|
expect(elements[0].y).toEqual(20);
|
||||||
|
expect(elements[0].width).toEqual(30); // 60 - 30
|
||||||
|
expect(elements[0].height).toEqual(50); // 70 - 20
|
||||||
|
});
|
||||||
|
|
||||||
|
it("diamond", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("diamond");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
// start from (30, 20)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
|
||||||
|
// move to (60,70)
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
|
||||||
|
// finish (position does not matter)
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(4);
|
||||||
|
expect(renderScene.mock.calls[3][1]).toBeNull();
|
||||||
|
|
||||||
|
const elements = renderScene.mock.calls[3][0];
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].type).toEqual("diamond");
|
||||||
|
expect(elements[0].x).toEqual(30);
|
||||||
|
expect(elements[0].y).toEqual(20);
|
||||||
|
expect(elements[0].width).toEqual(30); // 60 - 30
|
||||||
|
expect(elements[0].height).toEqual(50); // 70 - 20
|
||||||
|
});
|
||||||
|
|
||||||
|
it("arrow", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("arrow");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
// start from (30, 20)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
|
||||||
|
// move to (60,70)
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
|
||||||
|
// finish (position does not matter)
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(4);
|
||||||
|
expect(renderScene.mock.calls[3][1]).toBeNull();
|
||||||
|
const elements = renderScene.mock.calls[3][0];
|
||||||
|
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].type).toEqual("arrow");
|
||||||
|
expect(elements[0].x).toEqual(30);
|
||||||
|
expect(elements[0].y).toEqual(20);
|
||||||
|
expect(elements[0].points.length).toEqual(2);
|
||||||
|
expect(elements[0].points[0]).toEqual([0, 0]);
|
||||||
|
expect(elements[0].points[1]).toEqual([30, 50]); // (60 - 30, 70 - 20)
|
||||||
|
});
|
||||||
|
|
||||||
|
it("line", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("line");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
// start from (30, 20)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
|
||||||
|
// move to (60,70)
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
|
||||||
|
// finish (position does not matter)
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(4);
|
||||||
|
expect(renderScene.mock.calls[3][1]).toBeNull();
|
||||||
|
const elements = renderScene.mock.calls[3][0];
|
||||||
|
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].type).toEqual("line");
|
||||||
|
expect(elements[0].x).toEqual(30);
|
||||||
|
expect(elements[0].y).toEqual(20);
|
||||||
|
expect(elements[0].points.length).toEqual(2);
|
||||||
|
expect(elements[0].points[0]).toEqual([0, 0]);
|
||||||
|
expect(elements[0].points[1]).toEqual([30, 50]); // (60 - 30, 70 - 20)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("do not add element to the scene if size is too small", () => {
|
||||||
|
it("rectangle", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("rectangle");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
// start from (30, 20)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
|
||||||
|
// finish (position does not matter)
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(3);
|
||||||
|
expect(renderScene.mock.calls[2][1]).toBeNull();
|
||||||
|
const elements = renderScene.mock.calls[2][0];
|
||||||
|
|
||||||
|
expect(elements.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ellipse", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("ellipse");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
// start from (30, 20)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
|
||||||
|
// finish (position does not matter)
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(3);
|
||||||
|
expect(renderScene.mock.calls[2][1]).toBeNull();
|
||||||
|
const elements = renderScene.mock.calls[2][0];
|
||||||
|
|
||||||
|
expect(elements.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("diamond", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("diamond");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
// start from (30, 20)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
|
||||||
|
// finish (position does not matter)
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(3);
|
||||||
|
expect(renderScene.mock.calls[2][1]).toBeNull();
|
||||||
|
const elements = renderScene.mock.calls[2][0];
|
||||||
|
|
||||||
|
expect(elements.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("arrow", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("arrow");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
// start from (30, 20)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
|
||||||
|
// finish (position does not matter)
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
// we need to finalize it because arrows and lines enter multi-mode
|
||||||
|
fireEvent.keyDown(document, { key: KEYS.ENTER });
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(4);
|
||||||
|
expect(renderScene.mock.calls[3][1]).toBeNull();
|
||||||
|
const elements = renderScene.mock.calls[3][0];
|
||||||
|
|
||||||
|
expect(elements.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("line", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("line");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
// start from (30, 20)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
|
||||||
|
// finish (position does not matter)
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
// we need to finalize it because arrows and lines enter multi-mode
|
||||||
|
fireEvent.keyDown(document, { key: KEYS.ENTER });
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(4);
|
||||||
|
expect(renderScene.mock.calls[3][1]).toBeNull();
|
||||||
|
const elements = renderScene.mock.calls[3][0];
|
||||||
|
|
||||||
|
expect(elements.length).toEqual(0);
|
||||||
|
});
|
||||||
|
});
|
88
src/tests/move.test.tsx
Normal file
88
src/tests/move.test.tsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import { render, fireEvent } from "./test-utils";
|
||||||
|
import { App } from "../index";
|
||||||
|
import * as Renderer from "../renderer/renderScene";
|
||||||
|
|
||||||
|
// Unmount ReactDOM from root
|
||||||
|
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||||
|
|
||||||
|
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||||
|
beforeEach(() => {
|
||||||
|
localStorage.clear();
|
||||||
|
renderScene.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("move element", () => {
|
||||||
|
it("rectangle", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
{
|
||||||
|
// create element
|
||||||
|
const tool = getByToolName("rectangle");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(4);
|
||||||
|
const elements = renderScene.mock.calls[3][0];
|
||||||
|
const selectionElement = renderScene.mock.calls[3][1];
|
||||||
|
expect(selectionElement).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].isSelected).toBeTruthy();
|
||||||
|
expect([elements[0].x, elements[0].y]).toEqual([30, 20]);
|
||||||
|
|
||||||
|
renderScene.mockClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 50, clientY: 20 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 20, clientY: 40 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(3);
|
||||||
|
const elements = renderScene.mock.calls[2][0];
|
||||||
|
expect(renderScene.mock.calls[2][1]).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect([elements[0].x, elements[0].y]).toEqual([0, 40]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("duplicate element on move when ALT is clicked", () => {
|
||||||
|
it("rectangle", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
{
|
||||||
|
// create element
|
||||||
|
const tool = getByToolName("rectangle");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(4);
|
||||||
|
const elements = renderScene.mock.calls[3][0];
|
||||||
|
const selectionElement = renderScene.mock.calls[3][1];
|
||||||
|
expect(selectionElement).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].isSelected).toBeTruthy();
|
||||||
|
expect([elements[0].x, elements[0].y]).toEqual([30, 20]);
|
||||||
|
|
||||||
|
renderScene.mockClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 50, clientY: 20, altKey: true });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 20, clientY: 40 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(3);
|
||||||
|
const elements = renderScene.mock.calls[2][0];
|
||||||
|
expect(renderScene.mock.calls[2][1]).toBeNull();
|
||||||
|
expect(elements.length).toEqual(2);
|
||||||
|
// previous element should stay intact
|
||||||
|
expect([elements[0].x, elements[0].y]).toEqual([30, 20]);
|
||||||
|
expect([elements[1].x, elements[1].y]).toEqual([0, 40]);
|
||||||
|
});
|
||||||
|
});
|
140
src/tests/multiPointCreate.test.tsx
Normal file
140
src/tests/multiPointCreate.test.tsx
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import { render, fireEvent } from "./test-utils";
|
||||||
|
import { App } from "../index";
|
||||||
|
import * as Renderer from "../renderer/renderScene";
|
||||||
|
import { KEYS } from "../keys";
|
||||||
|
|
||||||
|
// Unmount ReactDOM from root
|
||||||
|
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||||
|
|
||||||
|
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||||
|
beforeEach(() => {
|
||||||
|
localStorage.clear();
|
||||||
|
renderScene.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("remove shape in non linear elements", () => {
|
||||||
|
it("rectangle", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("rectangle");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseUp(canvas, { clientX: 30, clientY: 30 });
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(3);
|
||||||
|
const elements = renderScene.mock.calls[2][0];
|
||||||
|
expect(elements.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ellipse", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("ellipse");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseUp(canvas, { clientX: 30, clientY: 30 });
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(3);
|
||||||
|
const elements = renderScene.mock.calls[2][0];
|
||||||
|
expect(elements.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("diamond", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("diamond");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseUp(canvas, { clientX: 30, clientY: 30 });
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(3);
|
||||||
|
const elements = renderScene.mock.calls[2][0];
|
||||||
|
expect(elements.length).toEqual(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("multi point mode in linear elements", () => {
|
||||||
|
it("arrow", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("arrow");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
// first point is added on mouse down
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 30 });
|
||||||
|
|
||||||
|
// second point, enable multi point
|
||||||
|
fireEvent.mouseUp(canvas, { clientX: 30, clientY: 30 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 50, clientY: 60 });
|
||||||
|
|
||||||
|
// third point
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 50, clientY: 60 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 100, clientY: 140 });
|
||||||
|
|
||||||
|
// done
|
||||||
|
fireEvent.mouseDown(canvas);
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
fireEvent.keyDown(document, { key: KEYS.ENTER });
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(8);
|
||||||
|
const elements = renderScene.mock.calls[7][0];
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
|
||||||
|
expect(elements[0].type).toEqual("arrow");
|
||||||
|
expect(elements[0].x).toEqual(30);
|
||||||
|
expect(elements[0].y).toEqual(30);
|
||||||
|
expect(elements[0].points).toEqual([
|
||||||
|
[0, 0],
|
||||||
|
[20, 30],
|
||||||
|
[70, 110],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("line", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("line");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
// first point is added on mouse down
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 30 });
|
||||||
|
|
||||||
|
// second point, enable multi point
|
||||||
|
fireEvent.mouseUp(canvas, { clientX: 30, clientY: 30 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 50, clientY: 60 });
|
||||||
|
|
||||||
|
// third point
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 50, clientY: 60 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 100, clientY: 140 });
|
||||||
|
|
||||||
|
// done
|
||||||
|
fireEvent.mouseDown(canvas);
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
fireEvent.keyDown(document, { key: KEYS.ENTER });
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(8);
|
||||||
|
const elements = renderScene.mock.calls[7][0];
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
|
||||||
|
expect(elements[0].type).toEqual("line");
|
||||||
|
expect(elements[0].x).toEqual(30);
|
||||||
|
expect(elements[0].y).toEqual(30);
|
||||||
|
expect(elements[0].points).toEqual([
|
||||||
|
[0, 0],
|
||||||
|
[20, 30],
|
||||||
|
[70, 110],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
32
src/tests/queries/toolQueries.ts
Normal file
32
src/tests/queries/toolQueries.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { queries, buildQueries } from "@testing-library/react";
|
||||||
|
|
||||||
|
const _getAllByToolName = (container: HTMLElement, tool: string) => {
|
||||||
|
const toolMap: { [propKey: string]: string } = {
|
||||||
|
selection: "Selection — S, 1",
|
||||||
|
rectangle: "Rectangle — R, 2",
|
||||||
|
diamond: "Diamond — D, 3",
|
||||||
|
ellipse: "Ellipse — E, 4",
|
||||||
|
arrow: "Arrow — A, 5",
|
||||||
|
line: "Line — L, 6",
|
||||||
|
};
|
||||||
|
|
||||||
|
const toolTitle = toolMap[tool as string];
|
||||||
|
return queries.getAllByTitle(container, toolTitle);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMultipleError = (c: any, tool: any) =>
|
||||||
|
`Found multiple elements with tool name: ${tool}`;
|
||||||
|
const getMissingError = (c: any, tool: any) =>
|
||||||
|
`Unable to find an element with tool name: ${tool}`;
|
||||||
|
|
||||||
|
export const [
|
||||||
|
queryByToolName,
|
||||||
|
getAllByToolName,
|
||||||
|
getByToolName,
|
||||||
|
findAllByToolName,
|
||||||
|
findByToolName,
|
||||||
|
] = buildQueries<string[]>(
|
||||||
|
_getAllByToolName,
|
||||||
|
getMultipleError,
|
||||||
|
getMissingError,
|
||||||
|
);
|
98
src/tests/resize.test.tsx
Normal file
98
src/tests/resize.test.tsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import { render, fireEvent } from "./test-utils";
|
||||||
|
import { App } from "../index";
|
||||||
|
import * as Renderer from "../renderer/renderScene";
|
||||||
|
|
||||||
|
// Unmount ReactDOM from root
|
||||||
|
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||||
|
|
||||||
|
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||||
|
beforeEach(() => {
|
||||||
|
localStorage.clear();
|
||||||
|
renderScene.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("resize element", () => {
|
||||||
|
it("rectangle", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
{
|
||||||
|
// create element
|
||||||
|
const tool = getByToolName("rectangle");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(4);
|
||||||
|
const elements = renderScene.mock.calls[3][0];
|
||||||
|
const selectionElement = renderScene.mock.calls[3][1];
|
||||||
|
expect(selectionElement).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].isSelected).toBeTruthy();
|
||||||
|
expect([elements[0].x, elements[0].y]).toEqual([30, 20]);
|
||||||
|
|
||||||
|
renderScene.mockClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// select the element first
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 50, clientY: 20 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
// select a handler rectangle (top-left)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 21, clientY: 13 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 20, clientY: 40 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(5);
|
||||||
|
const elements = renderScene.mock.calls[4][0];
|
||||||
|
expect(renderScene.mock.calls[4][1]).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect([elements[0].x, elements[0].y]).toEqual([29, 47]);
|
||||||
|
expect([elements[0].width, elements[0].height]).toEqual([31, 23]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("resize element with aspect ratio when SHIFT is clicked", () => {
|
||||||
|
it("rectangle", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
|
||||||
|
{
|
||||||
|
// create element
|
||||||
|
const tool = getByToolName("rectangle");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(4);
|
||||||
|
const elements = renderScene.mock.calls[3][0];
|
||||||
|
const selectionElement = renderScene.mock.calls[3][1];
|
||||||
|
expect(selectionElement).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].isSelected).toBeTruthy();
|
||||||
|
expect([elements[0].x, elements[0].y]).toEqual([30, 20]);
|
||||||
|
|
||||||
|
renderScene.mockClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// select the element first
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 50, clientY: 20 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
// select a handler rectangle (top-left)
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 21, clientY: 13 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 20, clientY: 40, shiftKey: true });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(5);
|
||||||
|
const elements = renderScene.mock.calls[4][0];
|
||||||
|
expect(renderScene.mock.calls[4][1]).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect([elements[0].x, elements[0].y]).toEqual([29, 39]);
|
||||||
|
expect([elements[0].width, elements[0].height]).toEqual([31, 31]);
|
||||||
|
});
|
||||||
|
});
|
211
src/tests/selection.test.tsx
Normal file
211
src/tests/selection.test.tsx
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import { render, fireEvent } from "./test-utils";
|
||||||
|
import { App } from "../index";
|
||||||
|
import * as Renderer from "../renderer/renderScene";
|
||||||
|
import { KEYS } from "../keys";
|
||||||
|
|
||||||
|
// Unmount ReactDOM from root
|
||||||
|
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||||
|
|
||||||
|
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||||
|
beforeEach(() => {
|
||||||
|
localStorage.clear();
|
||||||
|
renderScene.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("selection element", () => {
|
||||||
|
it("create selection element on mouse down", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("selection");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 60, clientY: 100 });
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(1);
|
||||||
|
const selectionElement = renderScene.mock.calls[0][1]!;
|
||||||
|
expect(selectionElement).not.toBeNull();
|
||||||
|
expect(selectionElement.type).toEqual("selection");
|
||||||
|
expect([selectionElement.x, selectionElement.y]).toEqual([60, 100]);
|
||||||
|
expect([selectionElement.width, selectionElement.height]).toEqual([0, 0]);
|
||||||
|
|
||||||
|
// TODO: There is a memory leak if mouse up is not triggered
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resize selection element on mouse move", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("selection");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 60, clientY: 100 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 150, clientY: 30 });
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(2);
|
||||||
|
const selectionElement = renderScene.mock.calls[1][1]!;
|
||||||
|
expect(selectionElement).not.toBeNull();
|
||||||
|
expect(selectionElement.type).toEqual("selection");
|
||||||
|
expect([selectionElement.x, selectionElement.y]).toEqual([60, 30]);
|
||||||
|
expect([selectionElement.width, selectionElement.height]).toEqual([90, 70]);
|
||||||
|
|
||||||
|
// TODO: There is a memory leak if mouse up is not triggered
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("remove selection element on mouse up", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
// select tool
|
||||||
|
const tool = getByToolName("selection");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 60, clientY: 100 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 150, clientY: 30 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(3);
|
||||||
|
const selectionElement = renderScene.mock.calls[2][1];
|
||||||
|
expect(selectionElement).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("select single element on the scene", () => {
|
||||||
|
it("rectangle", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
{
|
||||||
|
// create element
|
||||||
|
const tool = getByToolName("rectangle");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
fireEvent.keyDown(document, { key: KEYS.ESCAPE });
|
||||||
|
}
|
||||||
|
|
||||||
|
const tool = getByToolName("selection");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
// click on a line on the rectangle
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 45, clientY: 20 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(7);
|
||||||
|
const elements = renderScene.mock.calls[6][0];
|
||||||
|
const selectionElement = renderScene.mock.calls[6][1];
|
||||||
|
expect(selectionElement).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("diamond", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
{
|
||||||
|
// create element
|
||||||
|
const tool = getByToolName("diamond");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
fireEvent.keyDown(document, { key: KEYS.ESCAPE });
|
||||||
|
}
|
||||||
|
|
||||||
|
const tool = getByToolName("selection");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
// click on a line on the rectangle
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 45, clientY: 20 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(7);
|
||||||
|
const elements = renderScene.mock.calls[6][0];
|
||||||
|
const selectionElement = renderScene.mock.calls[6][1];
|
||||||
|
expect(selectionElement).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ellipse", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
{
|
||||||
|
// create element
|
||||||
|
const tool = getByToolName("ellipse");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
fireEvent.keyDown(document, { key: KEYS.ESCAPE });
|
||||||
|
}
|
||||||
|
|
||||||
|
const tool = getByToolName("selection");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
// click on a line on the rectangle
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 45, clientY: 20 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(7);
|
||||||
|
const elements = renderScene.mock.calls[6][0];
|
||||||
|
const selectionElement = renderScene.mock.calls[6][1];
|
||||||
|
expect(selectionElement).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("arrow", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
{
|
||||||
|
// create element
|
||||||
|
const tool = getByToolName("arrow");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
fireEvent.keyDown(document, { key: KEYS.ESCAPE });
|
||||||
|
}
|
||||||
|
|
||||||
|
const tool = getByToolName("selection");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
// click on a line on the rectangle
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 45, clientY: 20 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(7);
|
||||||
|
const elements = renderScene.mock.calls[6][0];
|
||||||
|
const selectionElement = renderScene.mock.calls[6][1];
|
||||||
|
expect(selectionElement).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("arrow", () => {
|
||||||
|
const { getByToolName, container } = render(<App />);
|
||||||
|
const canvas = container.querySelector("canvas")!;
|
||||||
|
{
|
||||||
|
// create element
|
||||||
|
const tool = getByToolName("line");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
|
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
fireEvent.keyDown(document, { key: KEYS.ESCAPE });
|
||||||
|
}
|
||||||
|
|
||||||
|
const tool = getByToolName("selection");
|
||||||
|
fireEvent.click(tool);
|
||||||
|
// click on a line on the rectangle
|
||||||
|
fireEvent.mouseDown(canvas, { clientX: 45, clientY: 20 });
|
||||||
|
fireEvent.mouseUp(canvas);
|
||||||
|
|
||||||
|
expect(renderScene).toHaveBeenCalledTimes(7);
|
||||||
|
const elements = renderScene.mock.calls[6][0];
|
||||||
|
const selectionElement = renderScene.mock.calls[6][1];
|
||||||
|
expect(selectionElement).toBeNull();
|
||||||
|
expect(elements.length).toEqual(1);
|
||||||
|
expect(elements[0].isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
30
src/tests/test-utils.ts
Normal file
30
src/tests/test-utils.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import {
|
||||||
|
render,
|
||||||
|
queries,
|
||||||
|
RenderResult,
|
||||||
|
RenderOptions,
|
||||||
|
} from "@testing-library/react";
|
||||||
|
|
||||||
|
import * as toolQueries from "./queries/toolQueries";
|
||||||
|
|
||||||
|
const customQueries = {
|
||||||
|
...queries,
|
||||||
|
...toolQueries,
|
||||||
|
};
|
||||||
|
|
||||||
|
type TestRenderFn = (
|
||||||
|
ui: React.ReactElement,
|
||||||
|
options?: Omit<RenderOptions, "queries">,
|
||||||
|
) => RenderResult<typeof customQueries>;
|
||||||
|
|
||||||
|
const renderApp: TestRenderFn = (ui, options) =>
|
||||||
|
render(ui, {
|
||||||
|
queries: customQueries,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
|
||||||
|
// re-export everything
|
||||||
|
export * from "@testing-library/react";
|
||||||
|
|
||||||
|
// override render method
|
||||||
|
export { renderApp as render };
|
Loading…
x
Reference in New Issue
Block a user