diff --git a/.size-snapshot.json b/.size-snapshot.json index f56f49bd8..26384befe 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "dnd.js": { - "bundled": 375284, - "minified": 135837, - "gzipped": 40524 + "bundled": 375362, + "minified": 135899, + "gzipped": 40559 }, "dnd.min.js": { - "bundled": 306859, - "minified": 108429, - "gzipped": 31342 + "bundled": 306915, + "minified": 108480, + "gzipped": 31380 }, "dnd.esm.js": { - "bundled": 242252, - "minified": 126027, - "gzipped": 32831, + "bundled": 242327, + "minified": 126101, + "gzipped": 32867, "treeshaked": { "rollup": { "code": 20995, "import_statements": 561 }, "webpack": { - "code": 24433 + "code": 24493 } } } diff --git a/package.json b/package.json index 86857e1f5..beddf93e3 100644 --- a/package.json +++ b/package.json @@ -111,6 +111,7 @@ "@storybook/react": "6.5.0-alpha.60", "@storybook/theming": "6.5.0-alpha.60", "@testing-library/dom": "8.13.0", + "@testing-library/jest-dom": "5.16.4", "@testing-library/react": "12.1.4", "@types/enzyme": "3.10.12", "@types/express": "4.17.13", @@ -129,7 +130,6 @@ "@types/seedrandom": "3.0.2", "@typescript-eslint/eslint-plugin": "5.18.0", "@typescript-eslint/parser": "5.18.0", - "@wojtekmaj/enzyme-adapter-react-17": "0.6.7", "babel-jest": "27.5.1", "babel-loader": "8.2.4", "babel-plugin-dev-expression": "0.2.3", @@ -140,8 +140,6 @@ "cypress": "9.5.3", "dotenv": "16.0.0", "emotion-theming": "11.0.0", - "enzyme": "3.11.0", - "enzyme-adapter-react-16": "1.15.6", "eslint": "8.13.0", "eslint-config-airbnb": "19.0.4", "eslint-config-prettier": "8.5.0", @@ -175,7 +173,6 @@ "react-16": "npm:react@16.14.0", "react-dom": "17.0.2", "react-dom-16": "npm:react-dom@16.14.0", - "react-test-renderer": "17.0.2", "react-virtualized": "9.22.3", "react-window": "1.8.6", "release-it": "14.14.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d3aa6b839..b0d2149bc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,7 @@ specifiers: '@storybook/react': 6.5.0-alpha.60 '@storybook/theming': 6.5.0-alpha.60 '@testing-library/dom': 8.13.0 + '@testing-library/jest-dom': 5.16.4 '@testing-library/react': 12.1.4 '@types/enzyme': 3.10.12 '@types/express': 4.17.13 @@ -56,7 +57,6 @@ specifiers: '@types/seedrandom': 3.0.2 '@typescript-eslint/eslint-plugin': 5.18.0 '@typescript-eslint/parser': 5.18.0 - '@wojtekmaj/enzyme-adapter-react-17': 0.6.7 babel-jest: 27.5.1 babel-loader: 8.2.4 babel-plugin-dev-expression: 0.2.3 @@ -68,8 +68,6 @@ specifiers: cypress: 9.5.3 dotenv: 16.0.0 emotion-theming: 11.0.0 - enzyme: 3.11.0 - enzyme-adapter-react-16: 1.15.6 eslint: 8.13.0 eslint-config-airbnb: 19.0.4 eslint-config-prettier: 8.5.0 @@ -106,7 +104,6 @@ specifiers: react-dom: 17.0.2 react-dom-16: npm:react-dom@16.14.0 react-redux: ^7.2.8 - react-test-renderer: 17.0.2 react-virtualized: 9.22.3 react-window: 1.8.6 redux: ^4.1.2 @@ -178,6 +175,7 @@ devDependencies: '@storybook/react': 6.5.0-alpha.60_53061357d4abbea43324b67fa10c9322 '@storybook/theming': 6.5.0-alpha.60_react-dom@17.0.2+react@17.0.2 '@testing-library/dom': 8.13.0 + '@testing-library/jest-dom': 5.16.4 '@testing-library/react': 12.1.4_react-dom@17.0.2+react@17.0.2 '@types/enzyme': 3.10.12 '@types/express': 4.17.13 @@ -196,7 +194,6 @@ devDependencies: '@types/seedrandom': 3.0.2 '@typescript-eslint/eslint-plugin': 5.18.0_0dd9be2ba5ed9805045f3fec8be848f5 '@typescript-eslint/parser': 5.18.0_eslint@8.13.0+typescript@4.6.3 - '@wojtekmaj/enzyme-adapter-react-17': 0.6.7_fae758709a8810ba97b4c03852dde4d0 babel-jest: 27.5.1_@babel+core@7.17.9 babel-loader: 8.2.4_acba72ea4bf9d339cdfcd8f55cdb7006 babel-plugin-dev-expression: 0.2.3_@babel+core@7.17.9 @@ -207,8 +204,6 @@ devDependencies: cypress: 9.5.3 dotenv: 16.0.0 emotion-theming: 11.0.0 - enzyme: 3.11.0 - enzyme-adapter-react-16: 1.15.6_fae758709a8810ba97b4c03852dde4d0 eslint: 8.13.0 eslint-config-airbnb: 19.0.4_98153b3cb1eb5f851029189077e45ffc eslint-config-prettier: 8.5.0_eslint@8.13.0 @@ -242,7 +237,6 @@ devDependencies: react-16: /react/16.14.0 react-dom: 17.0.2_react@17.0.2 react-dom-16: /react-dom/16.14.0_react@17.0.2 - react-test-renderer: 17.0.2_react@17.0.2 react-virtualized: 9.22.3_react-dom@17.0.2+react@17.0.2 react-window: 1.8.6_react-dom@17.0.2+react@17.0.2 release-it: 14.14.1 @@ -4522,8 +4516,8 @@ packages: pretty-format: 27.5.1 dev: true - /@testing-library/jest-dom/5.16.2: - resolution: {integrity: sha512-6ewxs1MXWwsBFZXIk4nKKskWANelkdUehchEOokHsN8X7c2eKXGw+77aRV63UU8f/DTSVUPLaGxdrj4lN7D/ug==} + /@testing-library/jest-dom/5.16.4: + resolution: {integrity: sha512-Gy+IoFutbMQcky0k+bqqumXZ1cTGswLsFqmNLzNdSKkU9KGV2u9oXhukCbbJ9/LRPKiqwxEE8VpV/+YZlfkPUA==} engines: {node: '>=8', npm: '>=6', yarn: '>=1'} dependencies: '@babel/runtime': 7.17.9 @@ -5473,36 +5467,6 @@ packages: '@xtuc/long': 4.2.2 dev: true - /@wojtekmaj/enzyme-adapter-react-17/0.6.7_fae758709a8810ba97b4c03852dde4d0: - resolution: {integrity: sha512-B+byiwi/T1bx5hcj9wc0fUL5Hlb5giSXJzcnEfJVl2j6dGV2NJfcxDBYX0WWwIxlzNiFz8kAvlkFWI2y/nscZQ==} - peerDependencies: - enzyme: ^3.0.0 - react: ^17.0.0-0 - react-dom: ^17.0.0-0 - dependencies: - '@wojtekmaj/enzyme-adapter-utils': 0.1.4_react@17.0.2 - enzyme: 3.11.0 - enzyme-shallow-equal: 1.0.4 - has: 1.0.3 - prop-types: 15.8.1 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 - react-is: 17.0.2 - react-test-renderer: 17.0.2_react@17.0.2 - dev: true - - /@wojtekmaj/enzyme-adapter-utils/0.1.4_react@17.0.2: - resolution: {integrity: sha512-ARGIQSIIv3oBia1m5Ihn1VU0FGmft6KPe39SBKTb8p7LSXO23YI4kNtc4M/cKoIY7P+IYdrZcgMObvedyjoSQA==} - peerDependencies: - react: ^17.0.0-0 - dependencies: - function.prototype.name: 1.1.5 - has: 1.0.3 - object.fromentries: 2.0.5 - prop-types: 15.8.1 - react: 17.0.2 - dev: true - /@xstate/react/1.6.3_7ce6a90b9093193255e12b5a0fae8c89: resolution: {integrity: sha512-NCUReRHPGvvCvj2yLZUTfR0qVp6+apc8G83oXSjN4rl89ZjyujiKrTff55bze/HrsvCsP/sUJASf2n0nzMF1KQ==} peerDependencies: @@ -5658,23 +5622,6 @@ packages: symbol.prototype.description: 1.0.5 dev: true - /airbnb-prop-types/2.16.0_react@17.0.2: - resolution: {integrity: sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg==} - peerDependencies: - react: ^0.14 || ^15.0.0 || ^16.0.0-alpha - dependencies: - array.prototype.find: 2.1.2 - function.prototype.name: 1.1.5 - is-regex: 1.1.4 - object-is: 1.1.5 - object.assign: 4.1.2 - object.entries: 1.1.5 - prop-types: 15.8.1 - prop-types-exact: 1.2.0 - react: 17.0.2 - react-is: 16.13.1 - dev: true - /ajv-errors/1.0.1_ajv@6.12.6: resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==} peerDependencies: @@ -5923,25 +5870,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /array.prototype.filter/1.0.1: - resolution: {integrity: sha512-Dk3Ty7N42Odk7PjU/Ci3zT4pLj20YvuVnneG/58ICM6bt4Ij5kZaJTVQ9TSaWaIECX2sFyz4KItkVZqHNnciqw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.3 - es-abstract: 1.19.1 - es-array-method-boxes-properly: 1.0.0 - is-string: 1.0.7 - dev: true - - /array.prototype.find/2.1.2: - resolution: {integrity: sha512-00S1O4ewO95OmmJW7EesWfQlrCrLEL8kZ40w3+GkLX2yTt0m2ggcePPa2uHPJ9KUmJvwRq+lCV9bD8Yim23x/Q==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.3 - es-abstract: 1.19.1 - dev: true - /array.prototype.flat/1.2.5: resolution: {integrity: sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==} engines: {node: '>= 0.4'} @@ -6948,29 +6876,6 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /cheerio-select/1.5.0: - resolution: {integrity: sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==} - dependencies: - css-select: 4.2.1 - css-what: 5.1.0 - domelementtype: 2.2.0 - domhandler: 4.3.0 - domutils: 2.8.0 - dev: true - - /cheerio/1.0.0-rc.10: - resolution: {integrity: sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==} - engines: {node: '>= 6'} - dependencies: - cheerio-select: 1.5.0 - dom-serializer: 1.3.2 - domhandler: 4.3.0 - htmlparser2: 6.1.0 - parse5: 6.0.1 - parse5-htmlparser2-tree-adapter: 6.0.1 - tslib: 2.3.1 - dev: true - /chokidar/2.1.8: resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies @@ -8285,10 +8190,6 @@ packages: path-type: 4.0.0 dev: true - /discontinuous-range/1.0.0: - resolution: {integrity: sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=} - dev: true - /doctrine/2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -8528,76 +8429,6 @@ packages: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} dev: true - /enzyme-adapter-react-16/1.15.6_fae758709a8810ba97b4c03852dde4d0: - resolution: {integrity: sha512-yFlVJCXh8T+mcQo8M6my9sPgeGzj85HSHi6Apgf1Cvq/7EL/J9+1JoJmJsRxZgyTvPMAqOEpRSu/Ii/ZpyOk0g==} - peerDependencies: - enzyme: ^3.0.0 - react: ^16.0.0-0 - react-dom: ^16.0.0-0 - dependencies: - enzyme: 3.11.0 - enzyme-adapter-utils: 1.14.0_react@17.0.2 - enzyme-shallow-equal: 1.0.4 - has: 1.0.3 - object.assign: 4.1.2 - object.values: 1.1.5 - prop-types: 15.8.1 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 - react-is: 16.13.1 - react-test-renderer: 16.14.0_react@17.0.2 - semver: 5.7.1 - dev: true - - /enzyme-adapter-utils/1.14.0_react@17.0.2: - resolution: {integrity: sha512-F/z/7SeLt+reKFcb7597IThpDp0bmzcH1E9Oabqv+o01cID2/YInlqHbFl7HzWBl4h3OdZYedtwNDOmSKkk0bg==} - peerDependencies: - react: 0.13.x || 0.14.x || ^15.0.0-0 || ^16.0.0-0 - dependencies: - airbnb-prop-types: 2.16.0_react@17.0.2 - function.prototype.name: 1.1.5 - has: 1.0.3 - object.assign: 4.1.2 - object.fromentries: 2.0.5 - prop-types: 15.8.1 - react: 17.0.2 - semver: 5.7.1 - dev: true - - /enzyme-shallow-equal/1.0.4: - resolution: {integrity: sha512-MttIwB8kKxypwHvRynuC3ahyNc+cFbR8mjVIltnmzQ0uKGqmsfO4bfBuLxb0beLNPhjblUEYvEbsg+VSygvF1Q==} - dependencies: - has: 1.0.3 - object-is: 1.1.5 - dev: true - - /enzyme/3.11.0: - resolution: {integrity: sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==} - dependencies: - array.prototype.flat: 1.2.5 - cheerio: 1.0.0-rc.10 - enzyme-shallow-equal: 1.0.4 - function.prototype.name: 1.1.5 - has: 1.0.3 - html-element-map: 1.3.1 - is-boolean-object: 1.1.2 - is-callable: 1.2.4 - is-number-object: 1.0.6 - is-regex: 1.1.4 - is-string: 1.0.7 - is-subset: 0.1.1 - lodash.escape: 4.0.1 - lodash.isequal: 4.5.0 - object-inspect: 1.12.0 - object-is: 1.1.5 - object.assign: 4.1.2 - object.entries: 1.1.5 - object.values: 1.1.5 - raf: 3.4.1 - rst-selector-parser: 2.2.3 - string.prototype.trim: 1.2.5 - dev: true - /errno/0.1.8: resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} hasBin: true @@ -10479,13 +10310,6 @@ packages: lru-cache: 6.0.0 dev: true - /html-element-map/1.3.1: - resolution: {integrity: sha512-6XMlxrAFX4UEEGxctfFnmrFaaZFNf9i5fNuV5wZ3WWQ4FVaNP1aX1LkX9j2mfEx1NpjeE/rL3nmgEn23GdFmrg==} - dependencies: - array.prototype.filter: 1.0.1 - call-bind: 1.0.2 - dev: true - /html-encoding-sniffer/2.0.1: resolution: {integrity: sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==} engines: {node: '>=10'} @@ -11223,10 +11047,6 @@ packages: has-tostringtag: 1.0.0 dev: true - /is-subset/0.1.1: - resolution: {integrity: sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=} - dev: true - /is-symbol/1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} @@ -12487,18 +12307,6 @@ packages: resolution: {integrity: sha1-gteb/zCmfEAF/9XiUVMArZyk168=} dev: true - /lodash.escape/4.0.1: - resolution: {integrity: sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=} - dev: true - - /lodash.flattendeep/4.4.0: - resolution: {integrity: sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=} - dev: true - - /lodash.isequal/4.5.0: - resolution: {integrity: sha1-QVxEePK8wwEgwizhDtMib30+GOA=} - dev: true - /lodash.ismatch/4.4.0: resolution: {integrity: sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=} dev: true @@ -13088,10 +12896,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /moo/0.5.1: - resolution: {integrity: sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==} - dev: true - /move-concurrently/1.0.1: resolution: {integrity: sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=} dependencies: @@ -13160,16 +12964,6 @@ packages: resolution: {integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=} dev: true - /nearley/2.20.1: - resolution: {integrity: sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==} - hasBin: true - dependencies: - commander: 2.20.3 - moo: 0.5.1 - railroad-diagrams: 1.0.0 - randexp: 0.4.6 - dev: true - /negotiator/0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -13360,14 +13154,6 @@ packages: resolution: {integrity: sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==} dev: true - /object-is/1.1.5: - resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.3 - dev: true - /object-keys/1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -13794,12 +13580,6 @@ packages: protocols: 1.4.8 dev: true - /parse5-htmlparser2-tree-adapter/6.0.1: - resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} - dependencies: - parse5: 6.0.1 - dev: true - /parse5/6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} dev: true @@ -14237,14 +14017,6 @@ packages: sisteransi: 1.0.5 dev: true - /prop-types-exact/1.2.0: - resolution: {integrity: sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA==} - dependencies: - has: 1.0.3 - object.assign: 4.1.2 - reflect.ownkeys: 0.2.0 - dev: true - /prop-types/15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: @@ -14411,28 +14183,10 @@ packages: resolution: {integrity: sha512-64wjDTI8NAkplC3WYF3DUBXmdx8AZF0ubxiicZi83BKW5hcdvMtbwDe6gpFBngTo6+XIJbfwmUP8lMa85UPK6A==} dev: true - /raf/3.4.1: - resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} - dependencies: - performance-now: 2.1.0 - dev: true - - /railroad-diagrams/1.0.0: - resolution: {integrity: sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=} - dev: true - /ramda/0.21.0: resolution: {integrity: sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=} dev: true - /randexp/0.4.6: - resolution: {integrity: sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==} - engines: {node: '>=0.12'} - dependencies: - discontinuous-range: 1.0.0 - ret: 0.1.15 - dev: true - /randombytes/2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: @@ -14653,16 +14407,6 @@ packages: react: 17.0.2 dev: true - /react-shallow-renderer/16.14.1_react@17.0.2: - resolution: {integrity: sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==} - peerDependencies: - react: ^16.0.0 || ^17.0.0 - dependencies: - object-assign: 4.1.1 - react: 17.0.2 - react-is: 17.0.2 - dev: true - /react-syntax-highlighter/13.5.3_react@17.0.2: resolution: {integrity: sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg==} peerDependencies: @@ -14689,30 +14433,6 @@ packages: refractor: 3.6.0 dev: true - /react-test-renderer/16.14.0_react@17.0.2: - resolution: {integrity: sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg==} - peerDependencies: - react: ^16.14.0 - dependencies: - object-assign: 4.1.1 - prop-types: 15.8.1 - react: 17.0.2 - react-is: 16.13.1 - scheduler: 0.19.1 - dev: true - - /react-test-renderer/17.0.2_react@17.0.2: - resolution: {integrity: sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==} - peerDependencies: - react: 17.0.2 - dependencies: - object-assign: 4.1.1 - react: 17.0.2 - react-is: 17.0.2 - react-shallow-renderer: 16.14.1_react@17.0.2 - scheduler: 0.20.2 - dev: true - /react-textarea-autosize/8.3.3_c8e45b4eb687790dba17b4e1c4b4273f: resolution: {integrity: sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==} engines: {node: '>=10'} @@ -14895,10 +14615,6 @@ packages: dependencies: '@babel/runtime': 7.17.9 - /reflect.ownkeys/0.2.0: - resolution: {integrity: sha1-dJrO7H8/34tj+SegSAnpDFwLNGA=} - dev: true - /refractor/3.6.0: resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} dependencies: @@ -15341,13 +15057,6 @@ packages: fsevents: 2.3.2 dev: true - /rst-selector-parser/2.2.3: - resolution: {integrity: sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=} - dependencies: - lodash.flattendeep: 4.4.0 - nearley: 2.20.1 - dev: true - /rsvp/4.8.5: resolution: {integrity: sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==} engines: {node: 6.* || >= 7.*} @@ -15938,7 +15647,7 @@ packages: '@storybook/core-events': 6.4.19 '@storybook/theming': 6.4.19_react-dom@17.0.2+react@17.0.2 '@testing-library/dom': 7.31.2 - '@testing-library/jest-dom': 5.16.2 + '@testing-library/jest-dom': 5.16.4 '@xstate/react': 1.6.3_7ce6a90b9093193255e12b5a0fae8c89 gzip-js: 0.3.2 react: 17.0.2 @@ -16049,15 +15758,6 @@ packages: es-abstract: 1.19.1 dev: true - /string.prototype.trim/1.2.5: - resolution: {integrity: sha512-Lnh17webJVsD6ECeovpVN17RlAKjmz4rF9S+8Y45CkMc/ufVpTkU3vZIyIC7sllQ1FCvObZnnCdNs/HXTUOTlg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.3 - es-abstract: 1.19.1 - dev: true - /string.prototype.trimend/1.0.4: resolution: {integrity: sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==} dependencies: diff --git a/src/view/placeholder/placeholder.tsx b/src/view/placeholder/placeholder.tsx index 66a2c5cf1..e2afd3acb 100644 --- a/src/view/placeholder/placeholder.tsx +++ b/src/view/placeholder/placeholder.tsx @@ -193,5 +193,3 @@ const Placeholder: FunctionComponent = (props) => { }; export default React.memo(Placeholder); -// enzyme does not work well with memo, so exporting the non-memo version -export const WithoutMemo = Placeholder; diff --git a/test/setup/env-setup.ts b/test/setup/env-setup.ts index 18dca5d47..edb87e45d 100644 --- a/test/setup/env-setup.ts +++ b/test/setup/env-setup.ts @@ -1,2 +1 @@ import './browser'; -import './enzyme'; diff --git a/test/setup/environment.ts b/test/setup/environment.ts index c487388ce..492d4d951 100644 --- a/test/setup/environment.ts +++ b/test/setup/environment.ts @@ -4,12 +4,20 @@ import JSDOMEnvironment from 'jest-environment-jsdom'; import { TextDecoder, TextEncoder } from 'util'; import attachRafStub from './attach-raf-stub'; +import transitionEventPolyfill from './transition-event-polyfill'; + +declare global { + interface ProcessEnv { + REACT_VERSION?: string; + } +} export default class MyJSDOMEnvironment extends JSDOMEnvironment { constructor(config: Config.ProjectConfig, context?: EnvironmentContext) { super(config, context); attachRafStub.call(this); + transitionEventPolyfill.call(this); // When importing jsdom in one of the test it throws an // error, because TextDecoder and TextEncoder are needed. diff --git a/test/setup/enzyme.ts b/test/setup/enzyme.ts deleted file mode 100644 index 2898c262c..000000000 --- a/test/setup/enzyme.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* eslint-disable global-require */ -// setting up global enzyme -import Enzyme from 'enzyme'; - -declare global { - interface ProcessEnv { - REACT_VERSION?: string; - } -} - -function getAdapter() { - if (process.env.REACT_VERSION === '16') { - return require('enzyme-adapter-react-16'); - } - return require('@wojtekmaj/enzyme-adapter-react-17'); -} - -const Adapter = getAdapter(); - -Enzyme.configure({ adapter: new Adapter() }); diff --git a/test/setup/test-setup.ts b/test/setup/test-setup.ts index ad5dbe9bb..efb06ea73 100644 --- a/test/setup/test-setup.ts +++ b/test/setup/test-setup.ts @@ -1,3 +1,5 @@ +import '@testing-library/jest-dom'; + // ensuring that each test has at least one assertion beforeEach(() => { expect.hasAssertions(); diff --git a/test/setup/transition-event-polyfill.ts b/test/setup/transition-event-polyfill.ts new file mode 100644 index 000000000..7b30415bf --- /dev/null +++ b/test/setup/transition-event-polyfill.ts @@ -0,0 +1,32 @@ +import type JSDOMEnvironment from 'jest-environment-jsdom'; + +/** + * @testing-library/dom and jsdom do not properly implement + * the TransitionEvent. So we are implementing our own polyfill. + * + * See: + * - https://github.com/testing-library/dom-testing-library/pull/865 + * - https://github.com/jsdom/jsdom/issues/1781 + * + * Inspirated by: https://codesandbox.io/s/bgfz1?file=%2Fsrc%2Findex.test.js%3A70-363 + */ +export default function transitionEventPolyfill(this: JSDOMEnvironment) { + class TransitionEvent extends this.global.Event { + readonly elapsedTime: number; + readonly propertyName: string; + readonly pseudoElement: string; + + constructor( + type: string, + transitionEventInitDict: TransitionEventInit = {}, + ) { + super(type, transitionEventInitDict); + + this.propertyName = transitionEventInitDict.propertyName || 'unknown'; + this.elapsedTime = transitionEventInitDict.elapsedTime || 0; + this.pseudoElement = transitionEventInitDict.pseudoElement || 'unknown'; + } + } + + this.global.TransitionEvent = TransitionEvent; +} diff --git a/test/unit/integration/drag-handle/sensor-marshal/click-blocking.spec.tsx b/test/unit/integration/drag-handle/sensor-marshal/click-blocking.spec.tsx index cec924b8b..631dd7ea3 100644 --- a/test/unit/integration/drag-handle/sensor-marshal/click-blocking.spec.tsx +++ b/test/unit/integration/drag-handle/sensor-marshal/click-blocking.spec.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { render, fireEvent, createEvent } from '@testing-library/react'; -import { act } from 'react-dom/test-utils'; +import { act, render, fireEvent, createEvent } from '@testing-library/react'; import { invariant } from '../../../../../src/invariant'; import type { SensorAPI, diff --git a/test/unit/integration/drag-handle/sensor-marshal/outdated-locks.spec.tsx b/test/unit/integration/drag-handle/sensor-marshal/outdated-locks.spec.tsx index 2dcfb282e..9973bfcd3 100644 --- a/test/unit/integration/drag-handle/sensor-marshal/outdated-locks.spec.tsx +++ b/test/unit/integration/drag-handle/sensor-marshal/outdated-locks.spec.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { render } from '@testing-library/react'; -import { act } from 'react-dom/test-utils'; +import { act, render } from '@testing-library/react'; import { invariant } from '../../../../../src/invariant'; import type { SensorAPI, diff --git a/test/unit/integration/drag-handle/touch-sensor/click-blocking.spec.tsx b/test/unit/integration/drag-handle/touch-sensor/click-blocking.spec.tsx index acdaa5e52..681e6341e 100644 --- a/test/unit/integration/drag-handle/touch-sensor/click-blocking.spec.tsx +++ b/test/unit/integration/drag-handle/touch-sensor/click-blocking.spec.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { fireEvent, render, createEvent } from '@testing-library/react'; -import { act } from 'react-dom/test-utils'; +import { act, fireEvent, render, createEvent } from '@testing-library/react'; import App from '../../util/app'; import { touch, simpleLift } from '../../util/controls'; diff --git a/test/unit/integration/reorder-render-sync.spec.tsx b/test/unit/integration/reorder-render-sync.spec.tsx index f99fe13ff..c01768bdb 100644 --- a/test/unit/integration/reorder-render-sync.spec.tsx +++ b/test/unit/integration/reorder-render-sync.spec.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { getRect } from 'css-box-model'; -// import { mount, type ReactWrapper } from 'enzyme'; import { render, fireEvent } from '@testing-library/react'; import { DragDropContext, Draggable, Droppable } from '../../../src'; import type { DropResult } from '../../../src'; diff --git a/test/unit/view/connected-droppable/child-render-behaviour.spec.tsx b/test/unit/view/connected-droppable/child-render-behaviour.spec.tsx index 675827e6c..e3d19f9ac 100644 --- a/test/unit/view/connected-droppable/child-render-behaviour.spec.tsx +++ b/test/unit/view/connected-droppable/child-render-behaviour.spec.tsx @@ -1,8 +1,7 @@ +import { render, screen } from '@testing-library/react'; import React, { Component } from 'react'; -import { mount } from 'enzyme'; import type { DroppableProvided } from '../../../../src/view/droppable/droppable-types'; import Droppable from '../../../../src/view/droppable/connected-droppable'; -import forceUpdate from '../../../util/force-update'; import { DragDropContext } from '../../../../src'; class Person extends Component<{ @@ -46,34 +45,32 @@ afterEach(() => { }); it('should render the child function when the parent renders', () => { - const wrapper = mount(); + const { unmount } = render(); expect(personRenderSpy).toHaveBeenCalledTimes(1); - expect(wrapper.find(Person).props().name).toBe('Jake'); + expect(screen.getByText(/Jake/)).toHaveTextContent('hello Jake'); - wrapper.unmount(); + unmount(); }); it('should render the child function when the parent re-renders', () => { - const wrapper = mount(); + const { rerender, unmount } = render(); - forceUpdate(wrapper); + rerender(); expect(personRenderSpy).toHaveBeenCalledTimes(2); - expect(wrapper.find(Person).props().name).toBe('Jake'); + expect(screen.getByText(/Jake/)).toHaveTextContent('hello Jake'); - wrapper.unmount(); + unmount(); }); it('should render the child function when the parents props changes that cause a re-render', () => { - const wrapper = mount(); + const { rerender, unmount } = render(); - wrapper.setProps({ - currentUser: 'Finn', - }); + rerender(); expect(personRenderSpy).toHaveBeenCalledTimes(2); - expect(wrapper.find(Person).props().name).toBe('Finn'); + expect(screen.getByText(/Finn/)).toHaveTextContent('hello Finn'); - wrapper.unmount(); + unmount(); }); diff --git a/test/unit/view/drag-drop-context/content-security-protection-nonce.spec.tsx b/test/unit/view/drag-drop-context/content-security-protection-nonce.spec.tsx index a80adda5b..a05c1a681 100644 --- a/test/unit/view/drag-drop-context/content-security-protection-nonce.spec.tsx +++ b/test/unit/view/drag-drop-context/content-security-protection-nonce.spec.tsx @@ -1,6 +1,5 @@ +import { render } from '@testing-library/react'; import React from 'react'; -import { mount } from 'enzyme'; -import type { ReactWrapper } from 'enzyme'; import DragDropContext from '../../../../src/view/drag-drop-context'; import { resetServerContext } from '../../../../src'; import * as attributes from '../../../../src/view/data-attributes'; @@ -9,7 +8,7 @@ it('should insert nonce into style tag', () => { const nonce = 'ThisShouldBeACryptographicallySecurePseudorandomNumber'; resetServerContext(); - const wrapper1: ReactWrapper = mount( + const { unmount } = render( {}}> {null} , @@ -18,5 +17,5 @@ it('should insert nonce into style tag', () => { const nonceAttribute = styleTag ? styleTag.getAttribute('nonce') : ''; expect(nonceAttribute).toEqual(nonce); - wrapper1.unmount(); + unmount(); }); diff --git a/test/unit/view/droppable/home-list-placeholder-cleanup.spec.ts b/test/unit/view/droppable/home-list-placeholder-cleanup.spec.ts deleted file mode 100644 index 9b3659d1e..000000000 --- a/test/unit/view/droppable/home-list-placeholder-cleanup.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { act } from 'react-dom/test-utils'; -import type { ReactWrapper } from 'enzyme'; -import mount from './util/mount'; -import { - homeOwnProps, - isNotOverHome, - homeAtRest, - homePostDropAnimation, -} from './util/get-props'; -import Placeholder from '../../../../src/view/placeholder'; - -it('should not display a placeholder after a flushed drag end in the home list', () => { - // dropping - const wrapper: ReactWrapper = mount({ - ownProps: homeOwnProps, - mapProps: isNotOverHome, - }); - - expect(wrapper.find(Placeholder)).toHaveLength(1); - - wrapper.setProps({ - ...homeAtRest, - }); - wrapper.update(); - - expect(wrapper.find(Placeholder)).toHaveLength(0); -}); - -it('should animate a placeholder closed in a home list after a drag', () => { - // dropping - const wrapper: ReactWrapper = mount({ - ownProps: homeOwnProps, - mapProps: isNotOverHome, - }); - - expect(wrapper.find(Placeholder)).toHaveLength(1); - - wrapper.setProps({ - ...homePostDropAnimation, - }); - wrapper.update(); - - expect(wrapper.find(Placeholder)).toHaveLength(1); - expect(homePostDropAnimation.shouldAnimatePlaceholder).toBe(true); - - // finishing the animation - act(() => { - wrapper.find(Placeholder).props().onClose(); - }); - - // let the wrapper know the react tree has changed - wrapper.update(); - - // placeholder is now gone - expect(wrapper.find(Placeholder)).toHaveLength(0); -}); diff --git a/test/unit/view/droppable/home-list-placeholder-cleanup.spec.tsx b/test/unit/view/droppable/home-list-placeholder-cleanup.spec.tsx new file mode 100644 index 000000000..1edae3e54 --- /dev/null +++ b/test/unit/view/droppable/home-list-placeholder-cleanup.spec.tsx @@ -0,0 +1,94 @@ +import { act, render } from '@testing-library/react'; +import React from 'react'; +import App from './util/app'; +import getStubber from './util/get-stubber'; +import { + homeOwnProps, + isNotOverHome, + homeAtRest, + homePostDropAnimation, +} from './util/get-props'; + +// Spy Placeholder component +jest.mock('../../../../src/view/placeholder', () => jest.fn()); +// eslint-disable-next-line import/newline-after-import, import/first +import _Placeholder from '../../../../src/view/placeholder'; +const Placeholder = jest.mocked(_Placeholder); +const { default: OriginalPlaceholder } = jest.requireActual<{ + default: typeof _Placeholder; +}>('../../../../src/view/placeholder'); + +beforeEach(() => { + Placeholder.mockImplementation((props: any) => { + return ; + }); +}); + +it('should not display a placeholder after a flushed drag end in the home list', async () => { + const WrappedComponent = getStubber(); + // dropping + const { rerender, container } = render( + , + ); + + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(1); + + rerender( + , + ); + + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(0); +}); + +it('should animate a placeholder closed in a home list after a drag', () => { + const WrappedComponent = getStubber(); + // dropping + const { rerender, container } = render( + , + ); + + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(1); + + rerender( + , + ); + + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(1); + expect(homePostDropAnimation.shouldAnimatePlaceholder).toBe(true); + + // finishing the animation + act(() => { + Placeholder.mock.calls[1][0].onClose(); + }); + + // placeholder is now gone + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(0); +}); diff --git a/test/unit/view/droppable/inner-ref-validation.spec.tsx b/test/unit/view/droppable/inner-ref-validation.spec.tsx index 1fcbc8199..6594bb447 100644 --- a/test/unit/view/droppable/inner-ref-validation.spec.tsx +++ b/test/unit/view/droppable/inner-ref-validation.spec.tsx @@ -1,6 +1,7 @@ +import { render } from '@testing-library/react'; import React from 'react'; import type { DroppableProvided } from '../../../../src/view/droppable/droppable-types'; -import mount from './util/mount'; +import App from './util/app'; import { withError } from '../../../util/console'; it('should warn a consumer if they have not provided a ref', () => { @@ -20,7 +21,7 @@ it('should warn a consumer if they have not provided a ref', () => { } withError(() => { - mount({ WrappedComponent: NoRef }); + render(); }); }); @@ -44,6 +45,6 @@ it('should throw a consumer if they have provided an SVGElement', () => { } withError(() => { - mount({ WrappedComponent: WithSVG }); + render(); }); }); diff --git a/test/unit/view/droppable/own-props-validation.spec.ts b/test/unit/view/droppable/own-props-validation.spec.tsx similarity index 72% rename from test/unit/view/droppable/own-props-validation.spec.ts rename to test/unit/view/droppable/own-props-validation.spec.tsx index 60ecb30fb..f4060813e 100644 --- a/test/unit/view/droppable/own-props-validation.spec.ts +++ b/test/unit/view/droppable/own-props-validation.spec.tsx @@ -1,5 +1,7 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ -import mount from './util/mount'; +import { render } from '@testing-library/react'; +import React from 'react'; +import App from './util/app'; import { homeOwnProps as defaultOwnProps } from './util/get-props'; import { withError } from '../../../util/console'; @@ -21,21 +23,21 @@ it('should throw if no droppableId is provided', () => { }; withError(() => { - // @ts-ignore: expect error - not provided + // @ts-expect-error ownProps.droppableId = undefined; - mount({ ownProps }); + render(); }); withError(() => { - // @ts-ignore: expect error - not a string + // @ts-expect-error ownProps.droppableId = null; - mount({ ownProps }); + render(); }); withError(() => { - // @ts-ignore: expect error - using number + // @ts-expect-error ownProps.droppableId = 3; - mount({ ownProps }); + render(); }); }); @@ -44,9 +46,9 @@ it('should throw if isDropDisabled is set to null', () => { ...defaultOwnProps, }; withError(() => { - // @ts-ignore: expect error - null + // @ts-expect-error ownProps.isDropDisabled = null; - mount({ ownProps }); + render(); }); }); @@ -55,9 +57,9 @@ it('should throw if isCombineEnabled is set to null', () => { ...defaultOwnProps, }; withError(() => { - // @ts-ignore: expect error - null + // @ts-expect-error ownProps.isCombineEnabled = null; - mount({ ownProps }); + render(); }); }); @@ -66,8 +68,8 @@ it('should throw if ignoreContainerClipping is set to null', () => { ...defaultOwnProps, }; withError(() => { - // @ts-ignore: expect error - null + // @ts-expect-error ownProps.ignoreContainerClipping = null; - mount({ ownProps }); + render(); }); }); diff --git a/test/unit/view/droppable/pass-through-snapshot.spec.ts b/test/unit/view/droppable/pass-through-snapshot.spec.tsx similarity index 55% rename from test/unit/view/droppable/pass-through-snapshot.spec.ts rename to test/unit/view/droppable/pass-through-snapshot.spec.tsx index fa37bbbbb..183233bd8 100644 --- a/test/unit/view/droppable/pass-through-snapshot.spec.ts +++ b/test/unit/view/droppable/pass-through-snapshot.spec.tsx @@ -1,5 +1,6 @@ -import type { ReactWrapper } from 'enzyme'; -import mount from './util/mount'; +import { render } from '@testing-library/react'; +import React from 'react'; +import App from './util/app'; import getStubber from './util/get-stubber'; import { isNotOverHome, @@ -15,32 +16,38 @@ const getLastSnapshot = (myMock: any) => { it('should let a consumer know when a foreign list is being dragged over', () => { const myMock = jest.fn(); - mount({ - ownProps: foreignOwnProps, - mapProps: isOverForeign, - WrappedComponent: getStubber(myMock), - }); + const WrappedComponent = getStubber(myMock); + + render( + , + ); expect(getLastSnapshot(myMock)).toEqual(isOverForeign.snapshot); }); it('should update snapshot as dragging over changes', () => { const myMock = jest.fn(); + const WrappedComponent = getStubber(myMock); - const wrapper: ReactWrapper = mount({ - mapProps: homeAtRest, - WrappedComponent: getStubber(myMock), - }); + const { rerender } = render( + , + ); expect(getLastSnapshot(myMock)).toBe(homeAtRest.snapshot); - wrapper.setProps(isOverHome); + rerender(); expect(getLastSnapshot(myMock)).toBe(isOverHome.snapshot); // now over foreign list - wrapper.setProps(isNotOverHome); + rerender( + , + ); expect(getLastSnapshot(myMock)).toBe(isNotOverHome.snapshot); // drag is now over - wrapper.setProps(homeAtRest); + rerender(); expect(getLastSnapshot(myMock)).toBe(homeAtRest.snapshot); }); diff --git a/test/unit/view/droppable/placeholder-setup-warning.spec.tsx b/test/unit/view/droppable/placeholder-setup-warning.spec.tsx index 30f9b3a25..a25892227 100644 --- a/test/unit/view/droppable/placeholder-setup-warning.spec.tsx +++ b/test/unit/view/droppable/placeholder-setup-warning.spec.tsx @@ -1,5 +1,5 @@ +import { render } from '@testing-library/react'; import React from 'react'; -import type { ReactWrapper } from 'enzyme'; import type { DroppableProvided } from '../../../../src/view/droppable/droppable-types'; import { homeAtRest, @@ -7,7 +7,7 @@ import { isOverForeign, isNotOverForeign, } from './util/get-props'; -import mount from './util/mount'; +import App from './util/app'; import { disableWarn } from '../../../util/console'; class WithNoPlaceholder extends React.Component<{ @@ -29,56 +29,76 @@ disableWarn(); describe('is over foreign', () => { it('should log a warning when mounting', () => { - const wrapper: ReactWrapper = mount({ - ownProps: foreignOwnProps, - mapProps: isOverForeign, - WrappedComponent: WithNoPlaceholder, - }); + const { unmount } = render( + , + ); expect(console.warn).toHaveBeenCalled(); - wrapper.unmount(); + unmount(); }); it('should log a warning when updating', () => { - const wrapper: ReactWrapper = mount({ - ownProps: foreignOwnProps, - mapProps: homeAtRest, - WrappedComponent: WithNoPlaceholder, - }); + const { rerender, unmount } = render( + , + ); expect(console.warn).not.toHaveBeenCalled(); - wrapper.setProps(isOverForeign); + rerender( + , + ); expect(console.warn).toHaveBeenCalled(); - wrapper.unmount(); + unmount(); }); }); describe('is not over foreign', () => { it('should not log a warning when mounting', () => { - const wrapper: ReactWrapper = mount({ - ownProps: foreignOwnProps, - mapProps: isNotOverForeign, - WrappedComponent: WithNoPlaceholder, - }); + const { unmount } = render( + , + ); expect(console.warn).not.toHaveBeenCalled(); - wrapper.unmount(); + unmount(); }); it('should not log a warning when updating', () => { - const wrapper: ReactWrapper = mount({ - ownProps: foreignOwnProps, - mapProps: homeAtRest, - WrappedComponent: WithNoPlaceholder, - }); + const { rerender, unmount } = render( + , + ); expect(console.warn).not.toHaveBeenCalled(); - wrapper.setProps(isNotOverForeign); + rerender( + , + ); expect(console.warn).not.toHaveBeenCalled(); - wrapper.unmount(); + unmount(); }); }); diff --git a/test/unit/view/droppable/placeholder.spec.ts b/test/unit/view/droppable/placeholder.spec.ts deleted file mode 100644 index e08f52c06..000000000 --- a/test/unit/view/droppable/placeholder.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { ReactWrapper } from 'enzyme'; -import mount from './util/mount'; -import { - foreignOwnProps, - isOverForeign, - homeOwnProps, - isOverHome, - isNotOverHome, - homeAtRest, - isNotOverForeign, -} from './util/get-props'; -import Placeholder from '../../../../src/view/placeholder'; - -describe('home list', () => { - it('should not render a placeholder when not dragging', () => { - const wrapper: ReactWrapper = mount({ - ownProps: homeOwnProps, - mapProps: homeAtRest, - }); - - expect(wrapper.find(Placeholder)).toHaveLength(0); - }); - - it('should render a placeholder when dragging over', () => { - const wrapper: ReactWrapper = mount({ - ownProps: homeOwnProps, - mapProps: isOverHome, - }); - - expect(wrapper.find(Placeholder)).toHaveLength(1); - }); - - it('should render a placeholder when dragging over nothing', () => { - const wrapper: ReactWrapper = mount({ - ownProps: homeOwnProps, - mapProps: isNotOverHome, - }); - - expect(wrapper.find(Placeholder)).toHaveLength(1); - }); - - it('should render a placeholder when dragging over a foreign list', () => { - const wrapper: ReactWrapper = mount({ - ownProps: homeOwnProps, - mapProps: isOverForeign, - }); - - expect(wrapper.find(Placeholder)).toHaveLength(1); - }); -}); - -describe('foreign', () => { - it('should not render a placeholder when not dragging', () => { - const wrapper: ReactWrapper = mount({ - ownProps: foreignOwnProps, - mapProps: homeAtRest, - }); - - expect(wrapper.find(Placeholder)).toHaveLength(0); - }); - - it('should render a placeholder when dragging over', () => { - const wrapper: ReactWrapper = mount({ - ownProps: foreignOwnProps, - mapProps: isOverForeign, - }); - - expect(wrapper.find(Placeholder)).toHaveLength(1); - }); - - it('should not render a placeholder when over nothing', () => { - const wrapper: ReactWrapper = mount({ - ownProps: foreignOwnProps, - mapProps: isNotOverForeign, - }); - - expect(wrapper.find(Placeholder)).toHaveLength(0); - }); -}); diff --git a/test/unit/view/droppable/placeholder.spec.tsx b/test/unit/view/droppable/placeholder.spec.tsx new file mode 100644 index 000000000..acf61df26 --- /dev/null +++ b/test/unit/view/droppable/placeholder.spec.tsx @@ -0,0 +1,86 @@ +import { render } from '@testing-library/react'; +import React from 'react'; +import App from './util/app'; +import { + foreignOwnProps, + isOverForeign, + homeOwnProps, + isOverHome, + isNotOverHome, + homeAtRest, + isNotOverForeign, +} from './util/get-props'; + +describe('home list', () => { + it('should not render a placeholder when not dragging', () => { + const { container } = render( + , + ); + + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(0); + }); + + it('should render a placeholder when dragging over', () => { + const { container } = render( + , + ); + + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(1); + }); + + it('should render a placeholder when dragging over nothing', () => { + const { container } = render( + , + ); + + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(1); + }); + + it('should render a placeholder when dragging over a foreign list', () => { + const { container } = render( + , + ); + + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(1); + }); +}); + +describe('foreign', () => { + it('should not render a placeholder when not dragging', () => { + const { container } = render( + , + ); + + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(0); + }); + + it('should render a placeholder when dragging over', () => { + const { container } = render( + , + ); + + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(1); + }); + + it('should not render a placeholder when over nothing', () => { + const { container } = render( + , + ); + + expect( + container.querySelectorAll('[data-rfd-placeholder-context-id]'), + ).toHaveLength(0); + }); +}); diff --git a/test/unit/view/droppable/update-max-window-scroll.spec.ts b/test/unit/view/droppable/update-max-window-scroll.spec.ts deleted file mode 100644 index 0e9434b6e..000000000 --- a/test/unit/view/droppable/update-max-window-scroll.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import type { ReactWrapper } from 'enzyme'; -import mount from './util/mount'; -import { homeOwnProps, isOverHome, isNotOverHome } from './util/get-props'; -import type { DispatchProps } from '../../../../src/view/droppable/droppable-types'; -import getMaxWindowScroll from '../../../../src/view/window/get-max-window-scroll'; -import Placeholder from '../../../../src/view/placeholder'; - -it('should update when a placeholder animation finishes', () => { - const dispatchProps: DispatchProps = { - updateViewportMaxScroll: jest.fn(), - }; - const wrapper: ReactWrapper = mount({ - ownProps: homeOwnProps, - mapProps: isOverHome, - dispatchProps, - isMovementAllowed: () => true, - }); - - wrapper.find(Placeholder).props().onTransitionEnd(); - - expect(dispatchProps.updateViewportMaxScroll).toHaveBeenCalledWith({ - maxScroll: getMaxWindowScroll(), - }); -}); - -it('should update when a placeholder finishes and the list is not dragged over', () => { - const dispatchProps: DispatchProps = { - updateViewportMaxScroll: jest.fn(), - }; - const wrapper: ReactWrapper = mount({ - ownProps: homeOwnProps, - mapProps: isNotOverHome, - dispatchProps, - isMovementAllowed: () => true, - }); - - wrapper.find(Placeholder).props().onTransitionEnd(); - - expect(dispatchProps.updateViewportMaxScroll).toHaveBeenCalledWith({ - maxScroll: getMaxWindowScroll(), - }); -}); - -it('should not update when dropping', () => { - const dispatchProps: DispatchProps = { - updateViewportMaxScroll: jest.fn(), - }; - const wrapper: ReactWrapper = mount({ - ownProps: homeOwnProps, - mapProps: isNotOverHome, - dispatchProps, - // when dropping there is no movement allowed - isMovementAllowed: () => false, - }); - - wrapper.find(Placeholder).props().onTransitionEnd(); - - expect(dispatchProps.updateViewportMaxScroll).not.toHaveBeenCalled(); -}); diff --git a/test/unit/view/droppable/update-max-window-scroll.spec.tsx b/test/unit/view/droppable/update-max-window-scroll.spec.tsx new file mode 100644 index 000000000..0f57aa151 --- /dev/null +++ b/test/unit/view/droppable/update-max-window-scroll.spec.tsx @@ -0,0 +1,80 @@ +import { render } from '@testing-library/react'; +import React from 'react'; +import App from './util/app'; +import { homeOwnProps, isOverHome, isNotOverHome } from './util/get-props'; +import type { DispatchProps } from '../../../../src/view/droppable/droppable-types'; +import getMaxWindowScroll from '../../../../src/view/window/get-max-window-scroll'; + +// Spy Placeholder component +jest.mock('../../../../src/view/placeholder', () => jest.fn()); +// eslint-disable-next-line import/newline-after-import, import/first +import _Placeholder from '../../../../src/view/placeholder'; +const Placeholder = jest.mocked(_Placeholder); +const { default: OriginalPlaceholder } = jest.requireActual<{ + default: typeof _Placeholder; +}>('../../../../src/view/placeholder'); + +beforeEach(() => { + Placeholder.mockImplementation((props: any) => { + return ; + }); +}); + +it('should update when a placeholder animation finishes', () => { + const dispatchProps: DispatchProps = { + updateViewportMaxScroll: jest.fn(), + }; + render( + true} + />, + ); + + Placeholder.mock.calls[0][0].onTransitionEnd(); + + expect(dispatchProps.updateViewportMaxScroll).toHaveBeenCalledWith({ + maxScroll: getMaxWindowScroll(), + }); +}); + +it('should update when a placeholder finishes and the list is not dragged over', () => { + const dispatchProps: DispatchProps = { + updateViewportMaxScroll: jest.fn(), + }; + render( + true} + />, + ); + + Placeholder.mock.calls[0][0].onTransitionEnd(); + + expect(dispatchProps.updateViewportMaxScroll).toHaveBeenCalledWith({ + maxScroll: getMaxWindowScroll(), + }); +}); + +it('should not update when dropping', () => { + const dispatchProps: DispatchProps = { + updateViewportMaxScroll: jest.fn(), + }; + render( + false} + />, + ); + + Placeholder.mock.calls[0][0].onTransitionEnd(); + + expect(dispatchProps.updateViewportMaxScroll).not.toHaveBeenCalled(); +}); diff --git a/test/unit/view/droppable/util/mount.tsx b/test/unit/view/droppable/util/app.tsx similarity index 88% rename from test/unit/view/droppable/util/mount.tsx rename to test/unit/view/droppable/util/app.tsx index 040e31bea..2937ddb8b 100644 --- a/test/unit/view/droppable/util/mount.tsx +++ b/test/unit/view/droppable/util/app.tsx @@ -1,5 +1,4 @@ import React, { useMemo } from 'react'; -import { mount } from 'enzyme'; import type { MapProps, DroppableProps, @@ -27,6 +26,7 @@ interface MountArgs { mapProps?: MapProps; dispatchProps?: DispatchProps; isMovementAllowed?: () => boolean; + overwriteProps?: Partial; } interface AppProps extends Props { @@ -69,13 +69,14 @@ export default ({ mapProps = homeAtRest, dispatchProps = defaultDispatchProps, isMovementAllowed = () => true, -}: MountArgs = {}) => - mount( - , - ); + overwriteProps = {}, +}: MountArgs) => ( + +); diff --git a/test/unit/view/placeholder/animated-mount.spec.tsx b/test/unit/view/placeholder/animated-mount.spec.tsx index 4dd59708c..89210a58d 100644 --- a/test/unit/view/placeholder/animated-mount.spec.tsx +++ b/test/unit/view/placeholder/animated-mount.spec.tsx @@ -1,8 +1,6 @@ +import { act, render } from '@testing-library/react'; import React from 'react'; -import { mount } from 'enzyme'; -import type { ReactWrapper } from 'enzyme'; -import { act } from 'react-dom/test-utils'; -import Placeholder from './util/placeholder-with-class'; +import Placeholder from '../../../../src/view/placeholder'; import { expectIsEmpty, expectIsFull } from './util/expect'; import { placeholder } from './util/data'; import getPlaceholderStyle from './util/get-placeholder-style'; @@ -37,20 +35,22 @@ const getCreatePlaceholderCalls = () => { }; it('should animate a mount', () => { - const wrapper: ReactWrapper = mount( + const onClose = jest.fn(); + const onTransitionEnd = jest.fn(); + const { container } = render( , ); expect(getCreatePlaceholderCalls().length).toBe(1); // first call had an empty size - const onMount = getPlaceholderStyle(wrapper); + const onMount = getPlaceholderStyle(container); expectIsEmpty(onMount); // Will trigger a .setState @@ -58,68 +58,79 @@ it('should animate a mount', () => { jest.runOnlyPendingTimers(); }); - // tell enzyme that something has changed - wrapper.update(); - - const postMount = getPlaceholderStyle(wrapper); + const postMount = getPlaceholderStyle(container); expectIsFull(postMount); }); it('should not animate a mount if interrupted', () => { - const wrapper: ReactWrapper = mount( + const onClose = jest.fn(); + const onTransitionEnd = jest.fn(); + const { container, rerender } = render( , ); - const onMount = getPlaceholderStyle(wrapper); + const onMount = getPlaceholderStyle(container); expectIsEmpty(onMount); expect(getCreatePlaceholderCalls()).toHaveLength(1); // interrupting animation - wrapper.setProps({ - animate: 'none', - }); + rerender( + , + ); // render 1: normal // render 2: useEffect calling setState // render 3: result of setState expect(getCreatePlaceholderCalls()).toHaveLength(3); - // no timers are run - // let enzyme know that the react tree has changed due to the set state - wrapper.update(); - - const postMount = getPlaceholderStyle(wrapper); + const postMount = getPlaceholderStyle(container); expectIsFull(postMount); // validation - no further updates spy.mockClear(); jest.runOnlyPendingTimers(); - wrapper.update(); - expectIsFull(getPlaceholderStyle(wrapper)); + rerender( + , + ); + expectIsFull(getPlaceholderStyle(container)); expect(getCreatePlaceholderCalls()).toHaveLength(0); }); it('should not animate in if unmounted', () => { + const onClose = jest.fn(); + const onTransitionEnd = jest.fn(); const error = jest.spyOn(console, 'error'); - const wrapper: ReactWrapper = mount( + const { container, unmount } = render( , ); - expectIsEmpty(getPlaceholderStyle(wrapper)); + expectIsEmpty(getPlaceholderStyle(container)); - wrapper.unmount(); + unmount(); jest.runOnlyPendingTimers(); // an internal setState would be triggered the timer was diff --git a/test/unit/view/placeholder/on-close.spec.tsx b/test/unit/view/placeholder/on-close.spec.tsx index 327cf1fc3..8350e61d7 100644 --- a/test/unit/view/placeholder/on-close.spec.tsx +++ b/test/unit/view/placeholder/on-close.spec.tsx @@ -1,34 +1,45 @@ +import { render } from '@testing-library/react'; +import { fireEvent } from '@testing-library/dom'; import React from 'react'; -import { mount } from 'enzyme'; -import type { ReactWrapper } from 'enzyme'; -import Placeholder from './util/placeholder-with-class'; +import Placeholder from '../../../../src/view/placeholder'; import { expectIsFull } from './util/expect'; import getPlaceholderStyle from './util/get-placeholder-style'; import { placeholder } from './util/data'; it('should only fire a single onClose event', () => { const onClose = jest.fn(); + const onTransitionEnd = jest.fn(); - const wrapper: ReactWrapper = mount( + const { container, rerender } = render( , ); - expectIsFull(getPlaceholderStyle(wrapper)); + expectIsFull(getPlaceholderStyle(container)); - wrapper.setProps({ - animate: 'close', - }); + rerender( + , + ); + + const placholder = container.querySelector( + '[data-rfd-placeholder-context-id]', + ) as HTMLElement; // not a complete event const height: Partial = { propertyName: 'height', }; - wrapper.simulate('transitionend', height); + fireEvent.transitionEnd(placholder, height); expect(onClose).toHaveBeenCalledTimes(1); onClose.mockClear(); @@ -42,35 +53,48 @@ it('should only fire a single onClose event', () => { const width: Partial = { propertyName: 'width', }; - wrapper.simulate('transitionend', margin); - wrapper.simulate('transitionend', width); + fireEvent.transitionEnd(placholder, margin); + fireEvent.transitionEnd(placholder, width); expect(onClose).not.toHaveBeenCalled(); }); it('should not fire an onClose if not closing when a transitionend occurs', () => { const onClose = jest.fn(); + const onTransitionEnd = jest.fn(); - const wrapper: ReactWrapper = mount( + const { container, rerender } = render( , ); + const placholder = container.querySelector( + '[data-rfd-placeholder-context-id]', + ) as HTMLElement; const assert = () => { // not a complete event const height: Partial = { propertyName: 'height', }; - wrapper.simulate('transitionend', height); + fireEvent.transitionEnd(placholder, height); expect(onClose).not.toHaveBeenCalled(); onClose.mockClear(); }; - expectIsFull(getPlaceholderStyle(wrapper)); + + expectIsFull(getPlaceholderStyle(container)); assert(); - wrapper.setProps({ animate: 'open' }); + rerender( + , + ); assert(); }); diff --git a/test/unit/view/placeholder/on-transition-end.spec.tsx b/test/unit/view/placeholder/on-transition-end.spec.tsx index dd103318d..fc947f2c0 100644 --- a/test/unit/view/placeholder/on-transition-end.spec.tsx +++ b/test/unit/view/placeholder/on-transition-end.spec.tsx @@ -1,8 +1,7 @@ +import { act, render } from '@testing-library/react'; +import { fireEvent } from '@testing-library/dom'; import React from 'react'; -import { mount } from 'enzyme'; -import type { ReactWrapper } from 'enzyme'; -import { act } from 'react-dom/test-utils'; -import Placeholder from './util/placeholder-with-class'; +import Placeholder from '../../../../src/view/placeholder'; import { expectIsFull } from './util/expect'; import getPlaceholderStyle from './util/get-placeholder-style'; import { placeholder } from './util/data'; @@ -19,7 +18,7 @@ it('should only fire a single transitionend event a single time when transitioni const onTransitionEnd = jest.fn(); const onClose = jest.fn(); - const wrapper: ReactWrapper = mount( + const { container } = render( { jest.runOnlyPendingTimers(); }); - // let enzyme know that the react tree has changed due to the set state - wrapper.update(); - expectIsFull(getPlaceholderStyle(wrapper)); + expectIsFull(getPlaceholderStyle(container)); // first event: a 'height' event will trigger the handler + const placholder = container.querySelector( + '[data-rfd-placeholder-context-id]', + ) as HTMLElement; + // not a complete event const height: Partial = { propertyName: 'height', }; - wrapper.simulate('transitionend', height); + fireEvent.transitionEnd(placholder, height); expect(onTransitionEnd).toHaveBeenCalledTimes(1); onTransitionEnd.mockClear(); @@ -56,12 +57,12 @@ it('should only fire a single transitionend event a single time when transitioni const width: Partial = { propertyName: 'width', }; - wrapper.simulate('transitionend', margin); - wrapper.simulate('transitionend', width); + fireEvent.transitionEnd(placholder, margin); + fireEvent.transitionEnd(placholder, width); expect(onTransitionEnd).not.toHaveBeenCalled(); // another transition event of height would trigger the handler - wrapper.simulate('transitionend', height); + fireEvent.transitionEnd(placholder, height); expect(onTransitionEnd).toHaveBeenCalledTimes(1); // validate: this should not have triggered any close events diff --git a/test/unit/view/placeholder/util/expect.ts b/test/unit/view/placeholder/util/expect.ts index 878e8b784..a0754a5b6 100644 --- a/test/unit/view/placeholder/util/expect.ts +++ b/test/unit/view/placeholder/util/expect.ts @@ -1,25 +1,19 @@ -import type { CSSProperties } from 'react'; -import type { PlaceholderStyle } from '../../../../../src/view/placeholder/placeholder-types'; import { placeholder } from './data'; -export const expectIsEmpty = ( - style: PlaceholderStyle | CSSProperties | null, -): void => { - expect(style?.width).toBe(0); - expect(style?.height).toBe(0); - expect(style?.marginTop).toBe(0); - expect(style?.marginRight).toBe(0); - expect(style?.marginBottom).toBe(0); - expect(style?.marginLeft).toBe(0); +export const expectIsEmpty = (style: CSSStyleDeclaration | null): void => { + expect(style?.width).toBe('0px'); + expect(style?.height).toBe('0px'); + expect(style?.marginTop).toBe('0px'); + expect(style?.marginRight).toBe('0px'); + expect(style?.marginBottom).toBe('0px'); + expect(style?.marginLeft).toBe('0px'); }; -export const expectIsFull = ( - style: PlaceholderStyle | CSSProperties | null, -): void => { - expect(style?.width).toBe(placeholder.client.borderBox.width); - expect(style?.height).toBe(placeholder.client.borderBox.height); - expect(style?.marginTop).toBe(placeholder.client.margin.top); - expect(style?.marginRight).toBe(placeholder.client.margin.right); - expect(style?.marginBottom).toBe(placeholder.client.margin.bottom); - expect(style?.marginLeft).toBe(placeholder.client.margin.left); +export const expectIsFull = (style: CSSStyleDeclaration | null): void => { + expect(style?.width).toBe(`${placeholder.client.borderBox.width}px`); + expect(style?.height).toBe(`${placeholder.client.borderBox.height}px`); + expect(style?.marginTop).toBe(`${placeholder.client.margin.top}px`); + expect(style?.marginRight).toBe(`${placeholder.client.margin.right}px`); + expect(style?.marginBottom).toBe(`${placeholder.client.margin.bottom}px`); + expect(style?.marginLeft).toBe(`${placeholder.client.margin.left}px`); }; diff --git a/test/unit/view/placeholder/util/get-placeholder-style.ts b/test/unit/view/placeholder/util/get-placeholder-style.ts index 8a2368eef..41dc0b4ac 100644 --- a/test/unit/view/placeholder/util/get-placeholder-style.ts +++ b/test/unit/view/placeholder/util/get-placeholder-style.ts @@ -1,9 +1,4 @@ -import type { CSSProperties } from 'react'; -import type { ReactWrapper } from 'enzyme'; -import type { PlaceholderStyle } from '../../../../../src/view/placeholder/placeholder-types'; import { placeholder } from './data'; -export default ( - wrapper: ReactWrapper, -): PlaceholderStyle | CSSProperties | null => - wrapper.find(placeholder.tagName).prop('style') || null; +export default (container: HTMLElement): CSSStyleDeclaration | null => + container.querySelector(placeholder.tagName)?.style || null; diff --git a/test/unit/view/placeholder/util/placeholder-with-class.tsx b/test/unit/view/placeholder/util/placeholder-with-class.tsx deleted file mode 100644 index d340e09b4..000000000 --- a/test/unit/view/placeholder/util/placeholder-with-class.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import { WithoutMemo } from '../../../../../src/view/placeholder/placeholder'; -import type { Props } from '../../../../../src/view/placeholder/placeholder'; - -// enzyme does not work well with memo, so exporting the non-memo version -// Using PureComponent to match behaviour of React.memo -export default class PlaceholderWithClass extends React.PureComponent { - render() { - return ; - } -} diff --git a/test/unit/view/style-marshal/style-marshal.spec.tsx b/test/unit/view/style-marshal/style-marshal.spec.tsx index a1f74e215..d2b8551f1 100644 --- a/test/unit/view/style-marshal/style-marshal.spec.tsx +++ b/test/unit/view/style-marshal/style-marshal.spec.tsx @@ -1,6 +1,6 @@ +import { render } from '@testing-library/react'; import React from 'react'; import type { ReactNode } from 'react'; -import { mount } from 'enzyme'; import type { ContextId } from '../../../../src/types'; import useStyleMarshal from '../../../../src/view/use-style-marshal'; import getStyles from '../../../../src/view/use-style-marshal/get-styles'; @@ -59,7 +59,7 @@ it('should not mount style tags until mounted', () => { expect(document.querySelector(alwaysSelector)).toBeFalsy(); // now mounting - const wrapper = mount( + const { unmount } = render( {getMock()}, ); @@ -71,37 +71,37 @@ it('should not mount style tags until mounted', () => { HTMLStyleElement, ); - wrapper.unmount(); + unmount(); }); it('should apply the resting dyanmic styles by default', () => { const contextId: ContextId = '2'; - const wrapper = mount( + const { unmount } = render( {getMock()}, ); const active: string = getDynamicStyleFromTag(contextId); expect(active).toEqual(getStyles(`${contextId}`).resting); - wrapper.unmount(); + unmount(); }); it('should apply the resting always styles by default', () => { const contextId: ContextId = '2'; - const wrapper = mount( + const { unmount } = render( {getMock()}, ); const always: string = getAlwaysStyleFromTag(contextId); expect(always).toEqual(getStyles(`${contextId}`).always); - wrapper.unmount(); + unmount(); }); it('should apply the dragging styles when asked', () => { const contextId: ContextId = '2'; const mock = getMock(); - const wrapper = mount( + const { unmount } = render( {mock}, ); const marshal: StyleMarshal = getMarshal(mock); @@ -111,13 +111,13 @@ it('should apply the dragging styles when asked', () => { const active: string = getDynamicStyleFromTag(contextId); expect(active).toEqual(getStyles(`${contextId}`).dragging); - wrapper.unmount(); + unmount(); }); it('should apply the drop animating styles when asked', () => { const contextId: ContextId = '2'; const mock = getMock(); - const wrapper = mount( + const { unmount } = render( {mock}, ); const marshal: StyleMarshal = getMarshal(mock); @@ -126,13 +126,13 @@ it('should apply the drop animating styles when asked', () => { const active: string = getDynamicStyleFromTag(contextId); expect(active).toEqual(getStyles(`${contextId}`).dropAnimating); - wrapper.unmount(); + unmount(); }); it('should apply the user cancel styles when asked', () => { const contextId: ContextId = '2'; const mock = getMock(); - const wrapper = mount( + const { unmount } = render( {mock}, ); const marshal: StyleMarshal = getMarshal(mock); @@ -141,12 +141,12 @@ it('should apply the user cancel styles when asked', () => { const active: string = getDynamicStyleFromTag(contextId); expect(active).toEqual(getStyles(`${contextId}`).userCancel); - wrapper.unmount(); + unmount(); }); it('should remove the style tag from the head when unmounting', () => { const contextId: ContextId = '2'; - const wrapper = mount( + const { unmount } = render( {getMock()}, ); const selector1: string = getDynamicStyleTagSelector(contextId); @@ -157,7 +157,7 @@ it('should remove the style tag from the head when unmounting', () => { expect(document.querySelector(selector2)).toBeTruthy(); // now unmounted - wrapper.unmount(); + unmount(); expect(document.querySelector(selector1)).not.toBeTruthy(); expect(document.querySelector(selector2)).not.toBeTruthy(); @@ -167,7 +167,7 @@ it('should allow subsequent updates', () => { const contextId: ContextId = '10'; const styles: Styles = getStyles(`${contextId}`); const mock = getMock(); - const wrapper = mount( + const { unmount } = render( {mock}, ); const marshal: StyleMarshal = getMarshal(mock); @@ -183,14 +183,14 @@ it('should allow subsequent updates', () => { expect(getDynamicStyleFromTag(contextId)).toEqual(styles.dropAnimating); }); - wrapper.unmount(); + unmount(); }); it('should insert nonce into tag attribute', () => { const contextId: ContextId = '2'; const nonce = 'ThisShouldBeACryptographicallySecurePseudoRandomNumber'; const mock = getMock(); - const wrapper = mount( + const { unmount } = render( {mock} , @@ -209,5 +209,5 @@ it('should insert nonce into tag attribute', () => { expect(alwaysStyleTagNonce).toEqual(nonce); // now unmounted - wrapper.unmount(); + unmount(); }); diff --git a/test/unit/view/use-draggable-publisher.spec.tsx b/test/unit/view/use-draggable-publisher.spec.tsx index 03ca89e11..2caa22a60 100644 --- a/test/unit/view/use-draggable-publisher.spec.tsx +++ b/test/unit/view/use-draggable-publisher.spec.tsx @@ -1,7 +1,6 @@ +import { render } from '@testing-library/react'; import React, { useRef, useCallback } from 'react'; import type { Spacing, Rect } from 'css-box-model'; -import { mount } from 'enzyme'; -import type { ReactWrapper } from 'enzyme'; import { useMemo } from 'use-memo-one'; import { invariant } from '../../../src/invariant'; import useDraggablePublisher from '../../../src/view/use-draggable-publisher'; @@ -10,7 +9,6 @@ import { getDraggableDimension, getComputedSpacing, } from '../../util/dimension'; -import forceUpdate from '../../util/force-update'; import type { DraggableId, DraggableDimension, @@ -78,7 +76,7 @@ describe('dimension registration', () => { it('should register itself when mounting', () => { const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.draggable, 'register'); - mount(); + render(); const expected: DraggableEntry = { // $ExpectError @@ -96,7 +94,7 @@ describe('dimension registration', () => { const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.draggable, 'register'); const unregisterSpy = jest.spyOn(registry.draggable, 'unregister'); - const wrapper = mount(); + const { unmount } = render(); const expected: DraggableEntry = { // $ExpectError @@ -113,7 +111,7 @@ describe('dimension registration', () => { const entry = registerSpy.mock.calls[0][0]; expect(entry).toEqual(expected); - wrapper.unmount(); + unmount(); expect(unregisterSpy).toHaveBeenCalledTimes(1); expect(unregisterSpy.mock.calls[0][0]).toBe(entry); }); @@ -123,7 +121,7 @@ describe('dimension registration', () => { const registerSpy = jest.spyOn(registry.draggable, 'register'); const updateSpy = jest.spyOn(registry.draggable, 'update'); const unregisterSpy = jest.spyOn(registry.draggable, 'unregister'); - const wrapper = mount(); + const { rerender } = render(); const expectedInitial: DraggableEntry = { // $ExpectError @@ -146,9 +144,7 @@ describe('dimension registration', () => { registerSpy.mockReset(); // updating the index - wrapper.setProps({ - index: 1000, - }); + rerender(); // Descriptor updated const expectedUpdate: DraggableEntry = { @@ -176,11 +172,11 @@ describe('dimension registration', () => { const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.draggable, 'register'); const updateSpy = jest.spyOn(registry.draggable, 'update'); - const wrapper = mount(); + const { rerender } = render(); expect(registerSpy).toHaveBeenCalledTimes(1); - forceUpdate(wrapper); + rerender(); expect(updateSpy).not.toHaveBeenCalled(); }); }); @@ -188,14 +184,10 @@ describe('dimension registration', () => { describe('dimension publishing', () => { // we are doing this rather than spying on the prototype. // Sometimes setRef was being provided with an element that did not have the mocked prototype :| - const setBoundingClientRect = ( - wrapper: ReactWrapper, - borderBox: Rect, - ) => { - const ref = wrapper.getDOMNode(); - invariant(ref); - - ref.getBoundingClientRect = () => setDOMRect(borderBox); + const setBoundingClientRect = (element: Element | null, borderBox: Rect) => { + invariant(element); + + element.getBoundingClientRect = () => setDOMRect(borderBox); }; it('should publish the dimensions of the target when requested', () => { @@ -219,7 +211,7 @@ describe('dimension publishing', () => { const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.draggable, 'register'); - const wrapper: ReactWrapper = mount( + const { container } = render( { />, ); - setBoundingClientRect(wrapper, expected.client.borderBox); + setBoundingClientRect( + container.firstElementChild, + expected.client.borderBox, + ); // pull the get dimension function out const getDimension: GetDraggableDimensionFn = @@ -266,7 +261,7 @@ describe('dimension publishing', () => { const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.draggable, 'register'); - const wrapper: ReactWrapper = mount( + const { container } = render( { />, ); - setBoundingClientRect(wrapper, expected.client.borderBox); + setBoundingClientRect( + container.firstElementChild, + expected.client.borderBox, + ); // pull the get dimension function out const getDimension: GetDraggableDimensionFn = @@ -307,7 +305,7 @@ describe('dimension publishing', () => { const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.draggable, 'register'); - const wrapper: ReactWrapper = mount( + const { container } = render( { />, ); - setBoundingClientRect(wrapper, expected.client.borderBox); + setBoundingClientRect( + container.firstElementChild, + expected.client.borderBox, + ); // pull the get dimension function out const getDimension: GetDraggableDimensionFn = @@ -357,7 +358,7 @@ describe('dimension publishing', () => { } const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.draggable, 'register'); - const wrapper: ReactWrapper = mount( + const { unmount } = render( , ); // pull the get dimension function out @@ -365,6 +366,6 @@ describe('dimension publishing', () => { registerSpy.mock.calls[0][0].getDimension; // when we call the get dimension function without a ref things will explode expect(getDimension).toThrow(); - wrapper.unmount(); + unmount(); }); }); diff --git a/test/unit/view/use-droppable-publisher/forced-scroll.spec.tsx b/test/unit/view/use-droppable-publisher/forced-scroll.spec.tsx index 719b3e7b3..ce779df1b 100644 --- a/test/unit/view/use-droppable-publisher/forced-scroll.spec.tsx +++ b/test/unit/view/use-droppable-publisher/forced-scroll.spec.tsx @@ -1,4 +1,4 @@ -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import React from 'react'; import { invariant } from '../../../../src/invariant'; import { getMarshalStub } from '../../../util/dimension-marshal'; @@ -27,14 +27,14 @@ it('should throw if the droppable has no closest scrollable', () => { const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); // no scroll parent - const wrapper = mount( + const { container } = render( , , ); - const droppable = wrapper.find('.droppable').getDOMNode(); + const droppable = container.querySelector('.droppable') as HTMLElement; invariant(droppable); - const parent = wrapper.find('.scroll-parent').getDOMNode(); + const parent = container.querySelector('.scroll-parent') as HTMLElement; invariant(parent); jest .spyOn(droppable, 'getBoundingClientRect') @@ -68,18 +68,18 @@ describe('there is a closest scrollable', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const container = wrapper - .find('.scroll-container') - .getDOMNode(); - invariant(container); + const scrollContainer = container.querySelector( + '.scroll-container', + ) as HTMLElement; + invariant(scrollContainer); - expect(container.scrollTop).toBe(0); - expect(container.scrollLeft).toBe(0); + expect(scrollContainer.scrollTop).toBe(0); + expect(scrollContainer.scrollLeft).toBe(0); // tell the droppable to watch for scrolling const callbacks: DroppableCallbacks = @@ -89,26 +89,26 @@ describe('there is a closest scrollable', () => { callbacks.scroll({ x: 500, y: 1000 }); - expect(container.scrollLeft).toBe(500); - expect(container.scrollTop).toBe(1000); + expect(scrollContainer.scrollLeft).toBe(500); + expect(scrollContainer.scrollTop).toBe(1000); }); it('should throw if asked to scoll while scroll is not currently being watched', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const container = wrapper - .find('.scroll-container') - .getDOMNode(); - invariant(container); - expect(container.scrollTop).toBe(0); - expect(container.scrollLeft).toBe(0); + const scrollContainer = container.querySelector( + '.scroll-container', + ) as HTMLElement; + invariant(scrollContainer); + expect(scrollContainer.scrollTop).toBe(0); + expect(scrollContainer.scrollLeft).toBe(0); // dimension not returned yet const callbacks: DroppableCallbacks = diff --git a/test/unit/view/use-droppable-publisher/is-combined-enabled-change.spec.tsx b/test/unit/view/use-droppable-publisher/is-combined-enabled-change.spec.tsx index dc86ae528..962ec9956 100644 --- a/test/unit/view/use-droppable-publisher/is-combined-enabled-change.spec.tsx +++ b/test/unit/view/use-droppable-publisher/is-combined-enabled-change.spec.tsx @@ -1,4 +1,4 @@ -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import React from 'react'; import { getMarshalStub } from '../../../util/dimension-marshal'; import { setViewport } from '../../../util/viewport'; @@ -8,8 +8,6 @@ import { ScrollableItem, WithAppContext, } from './util/shared'; -import forceUpdate from '../../../util/force-update'; -import PassThroughProps from '../../../util/pass-through-props'; import type { Registry, DroppableCallbacks, @@ -22,14 +20,10 @@ it('should publish updates to the enabled state when dragging', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( - - {(extra) => ( - - - - )} - , + const { rerender } = render( + + + , ); // not called yet expect(marshal.updateDroppableIsCombineEnabled).not.toHaveBeenCalled(); @@ -38,9 +32,11 @@ it('should publish updates to the enabled state when dragging', () => { callbacks.getDimensionAndWatchScroll(preset.windowScroll, scheduled); // changing to false - wrapper.setProps({ - isCombineEnabled: false, - }); + rerender( + + + , + ); expect(marshal.updateDroppableIsCombineEnabled).toHaveBeenCalledTimes(1); expect(marshal.updateDroppableIsCombineEnabled).toHaveBeenCalledWith( preset.home.descriptor.id, @@ -49,9 +45,11 @@ it('should publish updates to the enabled state when dragging', () => { marshal.updateDroppableIsCombineEnabled.mockClear(); // now setting to true - wrapper.setProps({ - isCombineEnabled: true, - }); + rerender( + + + , + ); expect(marshal.updateDroppableIsCombineEnabled).toHaveBeenCalledTimes(1); expect(marshal.updateDroppableIsCombineEnabled).toHaveBeenCalledWith( preset.home.descriptor.id, @@ -62,14 +60,10 @@ it('should publish updates to the enabled state when dragging', () => { it('should not publish updates to the enabled state when there is no drag', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); - const wrapper = mount( - - {(extra) => ( - - , - - )} - , + const { rerender } = render( + + , + , ); // not called yet @@ -77,9 +71,11 @@ it('should not publish updates to the enabled state when there is no drag', () = // no yet dragging - wrapper.setProps({ - isCombineEnabled: false, - }); + rerender( + + , + , + ); expect(marshal.updateDroppableIsCombineEnabled).not.toHaveBeenCalled(); }); @@ -88,14 +84,10 @@ it('should not publish updates when there is no change', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( - - {(extra) => ( - - , - - )} - , + const { rerender } = render( + + , + , ); // not called yet @@ -104,13 +96,20 @@ it('should not publish updates when there is no change', () => { callbacks.getDimensionAndWatchScroll(preset.windowScroll, scheduled); // no change - wrapper.setProps({ - isCombineEnabled: true, - }); + rerender( + + , + , + ); expect(marshal.updateDroppableIsCombineEnabled).not.toHaveBeenCalled(); marshal.updateDroppableIsCombineEnabled.mockReset(); - forceUpdate(wrapper); + // force update + rerender( + + , + , + ); expect(marshal.updateDroppableIsCombineEnabled).not.toHaveBeenCalled(); }); diff --git a/test/unit/view/use-droppable-publisher/is-enabled-change.spec.tsx b/test/unit/view/use-droppable-publisher/is-enabled-change.spec.tsx index 9649df3c9..86fda10f9 100644 --- a/test/unit/view/use-droppable-publisher/is-enabled-change.spec.tsx +++ b/test/unit/view/use-droppable-publisher/is-enabled-change.spec.tsx @@ -1,4 +1,4 @@ -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import React from 'react'; import { getMarshalStub } from '../../../util/dimension-marshal'; import { setViewport } from '../../../util/viewport'; @@ -8,8 +8,6 @@ import { ScrollableItem, WithAppContext, } from './util/shared'; -import forceUpdate from '../../../util/force-update'; -import PassThroughProps from '../../../util/pass-through-props'; import type { Registry, DroppableCallbacks, @@ -22,14 +20,10 @@ it('should publish updates to the enabled state when dragging', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( - - {(extra) => ( - - - - )} - , + const { rerender } = render( + + + , ); // not called yet expect(marshal.updateDroppableIsEnabled).not.toHaveBeenCalled(); @@ -38,9 +32,11 @@ it('should publish updates to the enabled state when dragging', () => { callbacks.getDimensionAndWatchScroll(preset.windowScroll, scheduled); const isDropDisabled = true; - wrapper.setProps({ - isDropDisabled, - }); + rerender( + + + , + ); expect(marshal.updateDroppableIsEnabled).toHaveBeenCalledTimes(1); expect(marshal.updateDroppableIsEnabled).toHaveBeenCalledWith( @@ -52,14 +48,10 @@ it('should publish updates to the enabled state when dragging', () => { it('should not publish updates to the enabled state when there is no drag', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); - const wrapper = mount( - - {(extra) => ( - - - - )} - , + const { rerender } = render( + + + , ); // not called yet @@ -67,9 +59,11 @@ it('should not publish updates to the enabled state when there is no drag', () = // no yet dragging - wrapper.setProps({ - isDropDisabled: true, - }); + rerender( + + + , + ); expect(marshal.updateDroppableIsEnabled).not.toHaveBeenCalled(); }); @@ -78,14 +72,10 @@ it('should not publish updates when there is no change', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( - - {(extra) => ( - - - - )} - , + const { rerender } = render( + + + , ); // not called yet @@ -94,14 +84,21 @@ it('should not publish updates when there is no change', () => { callbacks.getDimensionAndWatchScroll(preset.windowScroll, scheduled); // no change - wrapper.setProps({ - isDropDisabled: false, - }); + rerender( + + + , + ); expect(marshal.updateDroppableIsEnabled).not.toHaveBeenCalled(); // $ExpectError marshal.updateDroppableIsEnabled.mockReset(); - forceUpdate(wrapper); + // force update + rerender( + + + , + ); expect(marshal.updateDroppableIsEnabled).not.toHaveBeenCalled(); }); diff --git a/test/unit/view/use-droppable-publisher/publishing.spec.tsx b/test/unit/view/use-droppable-publisher/publishing.spec.tsx index 605d35ebf..9cc069bc1 100644 --- a/test/unit/view/use-droppable-publisher/publishing.spec.tsx +++ b/test/unit/view/use-droppable-publisher/publishing.spec.tsx @@ -1,8 +1,6 @@ +import { render } from '@testing-library/react'; import type { Position } from 'css-box-model'; -import { mount } from 'enzyme'; -import type { ReactWrapper } from 'enzyme'; import React from 'react'; -import { invariant } from '../../../../src/invariant'; import type { DroppableDimension, ScrollSize } from '../../../../src/types'; import { negate } from '../../../../src/state/position'; import { offsetByPosition } from '../../../../src/state/spacing'; @@ -49,7 +47,7 @@ it('should publish the dimensions of the target', () => { border, windowScroll: { x: 0, y: 0 }, }); - const wrapper: ReactWrapper = mount( + const { container } = render( { /> , ); - const el = wrapper.getDOMNode(); - invariant(el); + const el = container.firstElementChild as HTMLElement; jest .spyOn(el, 'getBoundingClientRect') .mockImplementation(() => setDOMRect(bigClient.borderBox)); @@ -100,7 +97,7 @@ it('should consider the window scroll when calculating dimensions', () => { windowScroll, }); - const wrapper: ReactWrapper = mount( + const { container } = render( { /> , ); - const el = wrapper.getDOMNode(); - invariant(el); + const el = container.firstElementChild as HTMLElement; jest .spyOn(el, 'getBoundingClientRect') .mockImplementation(() => setDOMRect(bigClient.borderBox)); @@ -138,13 +134,12 @@ describe('no closest scrollable', () => { padding, windowScroll: preset.windowScroll, }); - const wrapper = mount( + const { container } = render( , ); - const el = wrapper.find('.droppable').getDOMNode(); - invariant(el); + const el = container.querySelector('.droppable') as HTMLElement; jest .spyOn(el, 'getBoundingClientRect') .mockImplementation(() => setDOMRect(bigClient.borderBox)); @@ -196,13 +191,12 @@ describe('droppable is scrollable', () => { const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); // both the droppable and the parent are scrollable - const wrapper = mount( + const { container } = render( , ); - const el = wrapper.find('.droppable').getDOMNode(); - invariant(el); + const el = container.querySelector('.droppable') as HTMLElement; // returning smaller border box as this is what occurs when the element is scrollable jest .spyOn(el, 'getBoundingClientRect') @@ -261,13 +255,12 @@ describe('droppable is scrollable', () => { const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); // both the droppable and the parent are scrollable - const wrapper = mount( + const { container } = render( , ); - const el = wrapper.find('.droppable').getDOMNode(); - invariant(el); + const el = container.querySelector('.droppable') as HTMLElement; // returning smaller border box as this is what occurs when the element is scrollable jest .spyOn(el, 'getBoundingClientRect') @@ -320,17 +313,18 @@ describe('parent of droppable is scrollable', () => { }); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const droppable = wrapper.find('.droppable').getDOMNode(); - invariant(droppable); + const droppable = container.querySelector('.droppable') as HTMLElement; jest .spyOn(droppable, 'getBoundingClientRect') .mockImplementation(() => setDOMRect(bigClient.borderBox)); - const parent: HTMLElement = wrapper.find('.scroll-parent').getDOMNode(); + const parent: HTMLElement = container.querySelector( + '.scroll-parent', + ) as HTMLElement; jest .spyOn(parent, 'getBoundingClientRect') .mockImplementation(() => setDOMRect(smallFrameClient.borderBox)); @@ -380,14 +374,13 @@ describe('both droppable and parent is scrollable', () => { }); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , , ); - const droppable = wrapper.find('.droppable').getDOMNode(); - invariant(droppable); - const parent: HTMLElement = wrapper.find('.scroll-parent').getDOMNode(); + const droppable = container.querySelector('.droppable') as HTMLElement; + const parent = container.querySelector('.scroll-parent') as HTMLElement; jest .spyOn(droppable, 'getBoundingClientRect') .mockImplementation(() => setDOMRect(smallFrameClient.borderBox)); @@ -425,15 +418,15 @@ it('should capture the initial scroll of the closest scrollable', () => { const frameScroll: Position = { x: 10, y: 20 }; const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , , ); - const droppable = wrapper.find('.droppable').getDOMNode(); - invariant(droppable); - const parent: HTMLElement = wrapper.find('.scroll-parent').getDOMNode(); - invariant(parent); + const droppable = container.querySelector('.droppable') as HTMLElement; + const parent: HTMLElement = container.querySelector( + '.scroll-parent', + ) as HTMLElement; // manually setting the scroll of the parent node parent.scrollTop = frameScroll.y; parent.scrollLeft = frameScroll.x; @@ -485,7 +478,7 @@ it('should indicate if subject clipping is permitted based on the ignoreContaine // in this case the parent of the droppable is the closest scrollable const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const droppable = wrapper.find('.droppable').getDOMNode(); - invariant(droppable); - const parent: HTMLElement = wrapper.find('.scroll-parent').getDOMNode(); + const droppable = container.querySelector('.droppable') as HTMLElement; + const parent = container.querySelector('.scroll-parent') as HTMLElement; const scrollSize: ScrollSize = { scrollWidth: bigClient.paddingBox.width, scrollHeight: bigClient.paddingBox.height, diff --git a/test/unit/view/use-droppable-publisher/recollection.spec.tsx b/test/unit/view/use-droppable-publisher/recollection.spec.tsx index b96cb6356..4540493af 100644 --- a/test/unit/view/use-droppable-publisher/recollection.spec.tsx +++ b/test/unit/view/use-droppable-publisher/recollection.spec.tsx @@ -1,5 +1,5 @@ +import { render } from '@testing-library/react'; import type { Position } from 'css-box-model'; -import { mount } from 'enzyme'; import React from 'react'; import { invariant } from '../../../../src/invariant'; import type { DroppableDimension } from '../../../../src/types'; @@ -59,12 +59,12 @@ it('should recollect scroll if requested', () => { // both the droppable and the parent are scrollable const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const el = wrapper.find('.droppable').getDOMNode(); + const el = container.querySelector('.droppable') as HTMLElement; invariant(el); // returning smaller border box as this is what occurs when the element is scrollable jest @@ -100,7 +100,7 @@ it('should throw if there is no drag occurring when a recollection is requested' // both the droppable and the parent are scrollable const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - mount( + render( , @@ -116,7 +116,7 @@ it('should throw if there if recollecting from droppable that is not a scroll co // both the droppable and the parent are scrollable const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - mount( + render( , diff --git a/test/unit/view/use-droppable-publisher/registration.spec.tsx b/test/unit/view/use-droppable-publisher/registration.spec.tsx index 56545766a..86c53b241 100644 --- a/test/unit/view/use-droppable-publisher/registration.spec.tsx +++ b/test/unit/view/use-droppable-publisher/registration.spec.tsx @@ -1,11 +1,8 @@ -/* eslint-disable react/no-multi-comp */ -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import React from 'react'; import type { DroppableDescriptor } from '../../../../src/types'; -import forceUpdate from '../../../util/force-update'; import { preset, ScrollableItem, WithAppContext } from './util/shared'; import { setViewport } from '../../../util/viewport'; -import PassThroughProps from '../../../util/pass-through-props'; import type { Registry, DroppableEntry, @@ -18,7 +15,7 @@ it('should register itself when mounting', () => { const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - mount( + render( , @@ -41,7 +38,7 @@ it('should unregister itself when unmounting', () => { const registerSpy = jest.spyOn(registry.droppable, 'register'); const unregisterSpy = jest.spyOn(registry.droppable, 'unregister'); - const wrapper = mount( + const { unmount } = render( , @@ -51,7 +48,7 @@ it('should unregister itself when unmounting', () => { const entry = registerSpy.mock.calls[0][0]; - wrapper.unmount(); + unmount(); expect(unregisterSpy).toHaveBeenCalledTimes(1); expect(unregisterSpy).toHaveBeenCalledWith(entry); }); @@ -61,14 +58,10 @@ it('should update its registration when a descriptor property changes', () => { const registerSpy = jest.spyOn(registry.droppable, 'register'); const unregisterSpy = jest.spyOn(registry.droppable, 'unregister'); - const wrapper = mount( - - {(extra) => ( - - - - )} - , + const { rerender } = render( + + + , ); // $ExpectError: using awesome matchers @@ -85,9 +78,11 @@ it('should update its registration when a descriptor property changes', () => { registerSpy.mockClear(); // updating the index - wrapper.setProps({ - droppableId: 'some-new-id', - }); + rerender( + + + , + ); const updated: DroppableDescriptor = { ...preset.home.descriptor, id: 'some-new-id', @@ -112,7 +107,7 @@ it('should not update its registration when a descriptor property does not chang const registerSpy = jest.spyOn(registry.droppable, 'register'); const unregisterSpy = jest.spyOn(registry.droppable, 'unregister'); - const wrapper = mount( + const { rerender } = render( , @@ -121,7 +116,11 @@ it('should not update its registration when a descriptor property does not chang expect(unregisterSpy).not.toHaveBeenCalled(); registerSpy.mockClear(); - forceUpdate(wrapper); + rerender( + + + , + ); expect(unregisterSpy).not.toHaveBeenCalled(); expect(registerSpy).not.toHaveBeenCalled(); }); diff --git a/test/unit/view/use-droppable-publisher/scroll-watching.spec.tsx b/test/unit/view/use-droppable-publisher/scroll-watching.spec.tsx index d9d47b7fd..220955726 100644 --- a/test/unit/view/use-droppable-publisher/scroll-watching.spec.tsx +++ b/test/unit/view/use-droppable-publisher/scroll-watching.spec.tsx @@ -1,4 +1,4 @@ -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import React from 'react'; import type { Position } from 'css-box-model'; import { invariant } from '../../../../src/invariant'; @@ -30,15 +30,15 @@ describe('should immediately publish updates', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const container = wrapper - .find('.scroll-container') - .getDOMNode(); - invariant(container); + const scrollContainer = container.querySelector( + '.scroll-container', + ) as HTMLElement; + invariant(scrollContainer); // tell the droppable to watch for scrolling const callbacks: DroppableCallbacks = @@ -46,7 +46,7 @@ describe('should immediately publish updates', () => { // watch scroll will only be called after the dimension is requested callbacks.getDimensionAndWatchScroll(preset.windowScroll, immediate); - scroll(container, { x: 500, y: 1000 }); + scroll(scrollContainer, { x: 500, y: 1000 }); expect(marshal.updateDroppableScroll).toHaveBeenCalledWith( preset.home.descriptor.id, @@ -59,15 +59,15 @@ describe('should immediately publish updates', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const container = wrapper - .find('.scroll-container') - .getDOMNode(); - invariant(container); + const scrollContainer = container.querySelector( + '.scroll-container', + ) as HTMLElement; + invariant(scrollContainer); // tell the droppable to watch for scrolling const callbacks: DroppableCallbacks = registerSpy.mock.calls[0][0].callbacks; @@ -76,7 +76,7 @@ describe('should immediately publish updates', () => { callbacks.getDimensionAndWatchScroll(preset.windowScroll, immediate); // first event - scroll(container, { x: 500, y: 1000 }); + scroll(scrollContainer, { x: 500, y: 1000 }); expect(marshal.updateDroppableScroll).toHaveBeenCalledTimes(1); expect(marshal.updateDroppableScroll).toHaveBeenCalledWith( preset.home.descriptor.id, @@ -86,11 +86,11 @@ describe('should immediately publish updates', () => { marshal.updateDroppableScroll.mockReset(); // second event - scroll to same spot - scroll(container, { x: 500, y: 1000 }); + scroll(scrollContainer, { x: 500, y: 1000 }); expect(marshal.updateDroppableScroll).not.toHaveBeenCalled(); // third event - new value - scroll(container, { x: 500, y: 1001 }); + scroll(scrollContainer, { x: 500, y: 1001 }); expect(marshal.updateDroppableScroll).toHaveBeenCalledWith( preset.home.descriptor.id, { x: 500, y: 1001 }, @@ -103,15 +103,15 @@ describe('should schedule publish updates', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const container = wrapper - .find('.scroll-container') - .getDOMNode(); - invariant(container); + const scrollContainer = container.querySelector( + '.scroll-container', + ) as HTMLElement; + invariant(scrollContainer); // tell the droppable to watch for scrolling const callbacks: DroppableCallbacks = @@ -119,7 +119,7 @@ describe('should schedule publish updates', () => { // watch scroll will only be called after the dimension is requested callbacks.getDimensionAndWatchScroll(preset.windowScroll, scheduled); - scroll(container, { x: 500, y: 1000 }); + scroll(scrollContainer, { x: 500, y: 1000 }); // release the update animation frame requestAnimationFrame.step(); @@ -133,15 +133,15 @@ describe('should schedule publish updates', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const container = wrapper - .find('.scroll-container') - .getDOMNode(); - invariant(container); + const scrollContainer = container.querySelector( + '.scroll-container', + ) as HTMLElement; + invariant(scrollContainer); // tell the droppable to watch for scrolling const callbacks: DroppableCallbacks = registerSpy.mock.calls[0][0].callbacks; @@ -150,9 +150,9 @@ describe('should schedule publish updates', () => { callbacks.getDimensionAndWatchScroll(preset.windowScroll, scheduled); // first event - scroll(container, { x: 500, y: 1000 }); + scroll(scrollContainer, { x: 500, y: 1000 }); // second event in same frame - scroll(container, { x: 200, y: 800 }); + scroll(scrollContainer, { x: 200, y: 800 }); // release the update animation frame requestAnimationFrame.step(); @@ -173,15 +173,15 @@ describe('should schedule publish updates', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const container = wrapper - .find('.scroll-container') - .getDOMNode(); - invariant(container); + const scrollContainer = container.querySelector( + '.scroll-container', + ) as HTMLElement; + invariant(scrollContainer); // tell the droppable to watch for scrolling const callbacks: DroppableCallbacks = registerSpy.mock.calls[0][0].callbacks; @@ -190,7 +190,7 @@ describe('should schedule publish updates', () => { callbacks.getDimensionAndWatchScroll(preset.windowScroll, scheduled); // first event - scroll(container, { x: 500, y: 1000 }); + scroll(scrollContainer, { x: 500, y: 1000 }); // release the frame requestAnimationFrame.step(); expect(marshal.updateDroppableScroll).toHaveBeenCalledTimes(1); @@ -202,11 +202,11 @@ describe('should schedule publish updates', () => { marshal.updateDroppableScroll.mockReset(); // second event - scroll(container, { x: 501, y: 1001 }); + scroll(scrollContainer, { x: 501, y: 1001 }); // no frame to release change yet // third event - back to original value - scroll(container, { x: 500, y: 1000 }); + scroll(scrollContainer, { x: 500, y: 1000 }); // release the frame requestAnimationFrame.step(); expect(marshal.updateDroppableScroll).not.toHaveBeenCalled(); @@ -216,15 +216,15 @@ describe('should schedule publish updates', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const container = wrapper - .find('.scroll-container') - .getDOMNode(); - invariant(container); + const scrollContainer = container.querySelector( + '.scroll-container', + ) as HTMLElement; + invariant(scrollContainer); // tell the droppable to watch for scrolling const callbacks: DroppableCallbacks = registerSpy.mock.calls[0][0].callbacks; @@ -233,14 +233,14 @@ describe('should schedule publish updates', () => { callbacks.getDimensionAndWatchScroll(preset.windowScroll, scheduled); // first event - scroll(container, { x: 500, y: 1000 }); + scroll(scrollContainer, { x: 500, y: 1000 }); requestAnimationFrame.step(); expect(marshal.updateDroppableScroll).toHaveBeenCalledTimes(1); // $ExpectError marshal.updateDroppableScroll.mockReset(); // second event - scroll(container, { x: 400, y: 100 }); + scroll(scrollContainer, { x: 400, y: 100 }); // no animation frame to release event fired yet // unwatching before frame fired @@ -257,13 +257,15 @@ it('should stop watching scroll when no longer required to publish', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const container = wrapper.find('.scroll-container').getDOMNode(); - invariant(container); + const scrollContainer = container.querySelector( + '.scroll-container', + ) as HTMLElement; + invariant(scrollContainer); // tell the droppable to watch for scrolling const callbacks: DroppableCallbacks = registerSpy.mock.calls[0][0].callbacks; @@ -271,7 +273,7 @@ it('should stop watching scroll when no longer required to publish', () => { callbacks.getDimensionAndWatchScroll(preset.windowScroll, immediate); // first event - scroll(container, { x: 500, y: 1000 }); + scroll(scrollContainer, { x: 500, y: 1000 }); expect(marshal.updateDroppableScroll).toHaveBeenCalledTimes(1); // $ExpectError marshal.updateDroppableScroll.mockReset(); @@ -279,7 +281,7 @@ it('should stop watching scroll when no longer required to publish', () => { callbacks.dragStopped(); // scroll event after no longer watching - scroll(container, { x: 190, y: 400 }); + scroll(scrollContainer, { x: 190, y: 400 }); expect(marshal.updateDroppableScroll).not.toHaveBeenCalled(); }); @@ -290,23 +292,25 @@ it('should stop watching for scroll events when the component is unmounted', () const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container, unmount } = render( , ); - const container = wrapper.find('.scroll-container').getDOMNode(); - invariant(container); + const scrollContainer = container.querySelector( + '.scroll-container', + ) as HTMLElement; + invariant(scrollContainer); // tell the droppable to watch for scrolling const callbacks: DroppableCallbacks = registerSpy.mock.calls[0][0].callbacks; // watch scroll will only be called after the dimension is requested callbacks.getDimensionAndWatchScroll(preset.windowScroll, immediate); - wrapper.unmount(); + unmount(); // second event - will not fire any updates - scroll(container, { x: 100, y: 300 }); + scroll(scrollContainer, { x: 100, y: 300 }); expect(marshal.updateDroppableScroll).not.toHaveBeenCalled(); // also logs a warning expect(consoleWarnSpy).toHaveBeenCalled(); @@ -317,7 +321,7 @@ it('should throw an error if asked to watch a scroll when already listening for const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { unmount } = render( , @@ -333,7 +337,7 @@ it('should throw an error if asked to watch a scroll when already listening for // cleanup callbacks.dragStopped(); - wrapper.unmount(); + unmount(); }); // if this is not the case then it will break in IE11 @@ -341,15 +345,20 @@ it('should add and remove events with the same event options', () => { const marshal = getMarshalStub(); const registry: Registry = createRegistry(); const registerSpy = jest.spyOn(registry.droppable, 'register'); - const wrapper = mount( + const { container } = render( , ); - const container = wrapper.find('.scroll-container').getDOMNode(); - invariant(container); - const addEventListenerSpy = jest.spyOn(container, 'addEventListener'); - const removeEventListenerSpy = jest.spyOn(container, 'removeEventListener'); + const scrollContainer = container.querySelector( + '.scroll-container', + ) as HTMLElement; + invariant(scrollContainer); + const addEventListenerSpy = jest.spyOn(scrollContainer, 'addEventListener'); + const removeEventListenerSpy = jest.spyOn( + scrollContainer, + 'removeEventListener', + ); // tell the droppable to watch for scrolling const callbacks: DroppableCallbacks = registerSpy.mock.calls[0][0].callbacks; diff --git a/test/util/force-update.ts b/test/util/force-update.ts deleted file mode 100644 index 0de4a7c1e..000000000 --- a/test/util/force-update.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ReactWrapper } from 'enzyme'; - -// wrapper.update() no longer forces a render -// instead using wrapper.setProps({}); -// https://github.com/airbnb/enzyme/issues/1245 - -export default (wrapper: ReactWrapper) => wrapper.setProps({}); diff --git a/test/util/pass-through-props.tsx b/test/util/pass-through-props.tsx deleted file mode 100644 index 062f7810c..000000000 --- a/test/util/pass-through-props.tsx +++ /dev/null @@ -1,13 +0,0 @@ -type Props = { - [K in keyof T]: T[K]; -} & { - children: (value: Omit) => JSX.Element; -}; - -export default function PassThroughProps( - props: Props, -): JSX.Element { - const { children, ...rest } = props; - - return children(rest); -} diff --git a/test/util/user-input-util.ts b/test/util/user-input-util.ts deleted file mode 100644 index 3b554b2f6..000000000 --- a/test/util/user-input-util.ts +++ /dev/null @@ -1,128 +0,0 @@ -import type { ReactWrapper } from 'enzyme'; -import type { Position } from 'css-box-model'; - -const primaryButton = 0; -const origin: Position = { x: 0, y: 0 }; - -const getTouch = (client: Position, force: number): any => { - // window.Touch not supported in jest yet so just returning an object - - // const touch: Touch = new window.Touch({ - const touch = { - // const touch: Touch = { - identifier: Date.now(), - // being super generic here - target: window, - clientX: client.x, - clientY: client.y, - radiusX: 2.5, - radiusY: 2.5, - rotationAngle: 0, - force, - }; - - return touch; -}; - -export const dispatchWindowMouseEvent = ( - eventName: string, - client: Position = origin, - button: number = primaryButton, - options: any = {}, -): MouseEvent => { - const event = new window.MouseEvent(eventName, { - bubbles: true, - cancelable: true, - view: window, - clientX: client.x, - clientY: client.y, - button, - }); - - // override properties on the event itself - Object.assign(event, options); - - window.dispatchEvent(event); - return event; -}; - -export const dispatchWindowKeyDownEvent = (keyCode: number): KeyboardEvent => { - const event = new window.KeyboardEvent('keydown', { - bubbles: true, - cancelable: true, - keyCode, - }); - window.dispatchEvent(event); - return event; -}; - -export const dispatchWindowEvent = ( - eventName: string, - options: any = {}, -): Event => { - const event: Event = document.createEvent('Event'); - event.initEvent(eventName, true, true); - - // override properties on the event itself - Object.assign(event, options); - - window.dispatchEvent(event); - - return event; -}; - -export const dispatchWindowTouchEvent = ( - eventName: string, - client: Position = { x: 0, y: 0 }, - force = 0, - options: any = {}, -): Event => { - const touch = getTouch(client, force); - // window.TouchEvent constructor not supported in current version of Jest - // So using the old school document.createEvent \o/ - - const touchOptions = { - touches: [touch], - targetTouches: [], - changedTouches: [touch], - shiftKey: false, - }; - - return dispatchWindowEvent(eventName, { - ...touchOptions, - ...options, - }); -}; - -export const mouseEvent = ( - eventName: string, - wrapper: ReactWrapper, - client: Position = origin, - button: number = primaryButton, - options: any = {}, -): void => { - wrapper.simulate(eventName, { - button, - clientX: client.x, - clientY: client.y, - ...options, - }); -}; - -export const withKeyboard = - (keyCode: number) => - (wrapper: ReactWrapper, options: any = {}): void => { - wrapper.simulate('keydown', { keyCode, ...options }); - }; - -export const touchEvent = ( - eventName: string, - wrapper: ReactWrapper, - client: Position = { x: 0, y: 0 }, - force = 0, - options: any = {}, -): void => { - const touches: any[] = [getTouch(client, force)]; - - wrapper.simulate(eventName, { touches, ...options }); -};