From 986149d04d4eac0a9b3d156935f621fc8f858c2f Mon Sep 17 00:00:00 2001 From: Nick Bosland Date: Sat, 14 Sep 2024 18:53:42 +0200 Subject: [PATCH] Fixed an issue with mounting a parcel when StrictMode is enabled (#206) * Fixed an issue with mounting a parcel when StrictMode is enabled * Added changeset * Run parcel test with and without strict mode enabled * Properly setup the configuration of the react strict mode in th tests --- .changeset/nasty-gifts-check.md | 5 + package.json | 2 +- pnpm-lock.yaml | 280 ++++++++++++++++++++++-- src/parcel.js | 1 + src/parcel.test.js | 377 +++++++++++++++++--------------- 5 files changed, 463 insertions(+), 202 deletions(-) create mode 100644 .changeset/nasty-gifts-check.md diff --git a/.changeset/nasty-gifts-check.md b/.changeset/nasty-gifts-check.md new file mode 100644 index 0000000..bd61e4b --- /dev/null +++ b/.changeset/nasty-gifts-check.md @@ -0,0 +1,5 @@ +--- +"single-spa-react": patch +--- + +Fixed an issue with mounting a parcel when StrictMode is enabled diff --git a/package.json b/package.json index 0167a0b..93ab559 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "@rollup/plugin-commonjs": "^20.0.0", "@rollup/plugin-node-resolve": "^13.0.4", "@testing-library/jest-dom": "^5.14.1", - "@testing-library/react": "^13.1.1", + "@testing-library/react": "^14.2.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "auto": "^10.37.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f5d5a4..74861c7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,8 +50,8 @@ devDependencies: specifier: ^5.14.1 version: 5.14.1 '@testing-library/react': - specifier: ^13.1.1 - version: 13.1.1(react-dom@18.0.0)(react@18.0.0) + specifier: ^14.2.0 + version: 14.2.0(react-dom@18.0.0)(react@18.0.0) '@types/react': specifier: ^18.0.0 version: 18.0.6 @@ -2220,17 +2220,17 @@ packages: '@sinonjs/commons': 1.8.3 dev: true - /@testing-library/dom@8.5.0: - resolution: {integrity: sha512-O0fmHFaPlqaYCpa/cBL0cvroMridb9vZsMLacgIqrlxj+fd+bGF8UfAgwsLCHRF84KLBafWlm9CuOvxeNTlodw==} - engines: {node: '>=12'} + /@testing-library/dom@9.3.4: + resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==} + engines: {node: '>=14'} dependencies: '@babel/code-frame': 7.14.5 - '@babel/runtime': 7.15.4 - '@types/aria-query': 4.2.2 - aria-query: 4.2.2 + '@babel/runtime': 7.22.6 + '@types/aria-query': 5.0.4 + aria-query: 5.1.3 chalk: 4.1.2 - dom-accessibility-api: 0.5.7 - lz-string: 1.4.4 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 pretty-format: 27.2.0 dev: true @@ -2249,15 +2249,15 @@ packages: redent: 3.0.0 dev: true - /@testing-library/react@13.1.1(react-dom@18.0.0)(react@18.0.0): - resolution: {integrity: sha512-8mirlAa0OKaUvnqnZF6MdAh2tReYA2KtWVw1PKvaF5EcCZqgK5pl8iF+3uW90JdG5Ua2c2c2E2wtLdaug3dsVg==} - engines: {node: '>=12'} + /@testing-library/react@14.2.0(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-7uBnPHyOG6nDGCzv8SLeJbSa33ZoYw7swYpSLIgJvBALdq7l9zPNk33om4USrxy1lKTxXaVfufzLmq83WNfWIw==} + engines: {node: '>=14'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 dependencies: - '@babel/runtime': 7.15.4 - '@testing-library/dom': 8.5.0 + '@babel/runtime': 7.22.6 + '@testing-library/dom': 9.3.4 '@types/react-dom': 18.0.2 react: 18.0.0 react-dom: 18.0.0(react@18.0.0) @@ -2289,8 +2289,8 @@ packages: hasBin: true dev: true - /@types/aria-query@4.2.2: - resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==} + /@types/aria-query@5.0.4: + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} dev: true /@types/babel__core@7.1.16: @@ -2603,6 +2603,12 @@ packages: '@babel/runtime-corejs3': 7.15.4 dev: true + /aria-query@5.1.3: + resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + dependencies: + deep-equal: 2.2.3 + dev: true + /array-back@3.1.0: resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==} engines: {node: '>=6'} @@ -2740,6 +2746,13 @@ packages: engines: {node: '>= 0.4'} dev: true + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 + dev: true + /await-to-js@3.0.0: resolution: {integrity: sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==} engines: {node: '>=6.0.0'} @@ -2950,6 +2963,17 @@ packages: get-intrinsic: 1.1.1 dev: true + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + dev: true + /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -3340,6 +3364,30 @@ packages: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} dev: true + /deep-equal@2.2.3: + resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.7 + es-get-iterator: 1.1.3 + get-intrinsic: 1.2.4 + is-arguments: 1.1.1 + is-array-buffer: 3.0.2 + is-date-object: 1.0.5 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + isarray: 2.0.5 + object-is: 1.1.6 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.5.2 + side-channel: 1.0.4 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.2 + which-typed-array: 1.1.15 + dev: true + /deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -3360,6 +3408,15 @@ packages: clone: 1.0.4 dev: true + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + dev: true + /define-properties@1.1.3: resolution: {integrity: sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==} engines: {node: '>= 0.4'} @@ -3375,6 +3432,15 @@ packages: object-keys: 1.1.1 dev: true + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + dev: true + /delayed-stream@1.0.0: resolution: {integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk=} engines: {node: '>=0.4.0'} @@ -3425,6 +3491,10 @@ packages: esutils: 2.0.3 dev: true + /dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dev: true + /dom-accessibility-api@0.5.7: resolution: {integrity: sha512-ml3lJIq9YjUfM9TUnEPvEYWFSwivwIGBPKpewX7tii7fwCazA8yCioGdqQcNsItPpfFvSJ3VIdMQPj60LJhcQA==} dev: true @@ -3565,6 +3635,32 @@ packages: which-typed-array: 1.1.11 dev: true + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + dev: true + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + dev: true + + /es-get-iterator@1.1.3: + resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + is-arguments: 1.1.1 + is-map: 2.0.3 + is-set: 2.0.3 + is-string: 1.0.7 + isarray: 2.0.5 + stop-iteration-iterator: 1.0.0 + dev: true + /es-set-tostringtag@2.0.1: resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} engines: {node: '>= 0.4'} @@ -4035,6 +4131,10 @@ packages: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} dev: true + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + /function.prototype.name@1.1.5: resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} engines: {node: '>= 0.4'} @@ -4088,6 +4188,17 @@ packages: has-symbols: 1.0.3 dev: true + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.2 + dev: true + /get-monorepo-packages@1.2.0: resolution: {integrity: sha512-aDP6tH+eM3EuVSp3YyCutOcFS4Y9AhRRH9FAd+cjtR/g63Hx+DCXdKoP1ViRPUJz5wm+BOEXB4FhoffGHxJ7jQ==} dependencies: @@ -4241,6 +4352,12 @@ packages: get-intrinsic: 1.1.1 dev: true + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + dependencies: + es-define-property: 1.0.0 + dev: true + /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} @@ -4268,6 +4385,13 @@ packages: has-symbols: 1.0.3 dev: true + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} @@ -4275,6 +4399,13 @@ packages: function-bind: 1.1.1 dev: true + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true @@ -4437,6 +4568,14 @@ packages: engines: {node: '>=8'} dev: true + /is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.0 + dev: true + /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: @@ -4504,6 +4643,13 @@ packages: engines: {node: '>= 0.4'} dev: true + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + /is-extglob@2.1.1: resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=} engines: {node: '>=0.10.0'} @@ -4526,6 +4672,11 @@ packages: is-extglob: 2.1.1 dev: true + /is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + dev: true + /is-module@1.0.0: resolution: {integrity: sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=} dev: true @@ -4587,6 +4738,11 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + dev: true + /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: @@ -4640,12 +4796,25 @@ packages: engines: {node: '>=10'} dev: true + /is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + dev: true + /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.2 dev: true + /is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + dev: true + /is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} @@ -5462,8 +5631,8 @@ packages: yallist: 4.0.0 dev: true - /lz-string@1.4.4: - resolution: {integrity: sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=} + /lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true dev: true @@ -5715,6 +5884,14 @@ packages: resolution: {integrity: sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==} dev: true + /object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + dev: true + /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -5995,6 +6172,11 @@ packages: irregular-plurals: 3.3.0 dev: true + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: true + /preferred-pm@3.0.3: resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==} engines: {node: '>=10'} @@ -6240,6 +6422,16 @@ packages: functions-have-names: 1.2.3 dev: true + /regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + dev: true + /regexpp@3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} @@ -6468,6 +6660,28 @@ packages: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + dev: true + + /set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + dev: true + /shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} @@ -6637,6 +6851,13 @@ packages: escape-string-regexp: 2.0.0 dev: true + /stop-iteration-iterator@1.0.0: + resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} + engines: {node: '>= 0.4'} + dependencies: + internal-slot: 1.0.5 + dev: true + /stream-transform@2.1.3: resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} dependencies: @@ -7294,6 +7515,16 @@ packages: is-symbol: 1.0.3 dev: true + /which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.3 + dev: true + /which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} dev: true @@ -7317,6 +7548,17 @@ packages: has-tostringtag: 1.0.0 dev: true + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + dev: true + /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true diff --git a/src/parcel.js b/src/parcel.js index 9e7fde9..b1ce072 100644 --- a/src/parcel.js +++ b/src/parcel.js @@ -26,6 +26,7 @@ export default class Parcel extends React.Component { } } componentDidMount() { + this.unmounted = false; this.addThingToDo("mount", () => { const mountParcel = this.props.mountParcel || this.mountParcel; if (!mountParcel) { diff --git a/src/parcel.test.js b/src/parcel.test.js index b695dc7..4cd340a 100644 --- a/src/parcel.test.js +++ b/src/parcel.test.js @@ -2,200 +2,213 @@ import * as React from "react"; import * as ReactDOM from "react-dom"; import * as ReactDOMClient from "react-dom/client"; // React >= 18 import Parcel from "./parcel.js"; -import { render, waitFor } from "@testing-library/react"; +import { configure, render, waitFor } from "@testing-library/react"; import "@testing-library/jest-dom/extend-expect"; import singleSpaReact, { SingleSpaContext } from "./single-spa-react"; import { jest } from "@jest/globals"; -describe(``, () => { - let config, - mountParcel = jest.fn(), - parcel, - props; - - beforeEach(() => { - config = { - bootstrap: jest.fn(), - mount: jest.fn(), - unmount: jest.fn(), - }; - - parcel = { - loadPromise: jest.fn(), - bootstrapPromise: jest.fn(), - mountPromise: Promise.resolve(), - unmountPromise: jest.fn(), - getStatus: jest.fn(), - unmount: jest.fn(), - update: jest.fn(), - }; - - mountParcel.mockReset(); - mountParcel.mockReturnValue(parcel); - - props = { mountParcel, config }; - jest.spyOn(console, "error").mockReturnValue(undefined); - }); - - it(`throws an error if you try to render the component without a config`, () => { - expect(() => { - render(); - }).toThrow(); - }); - - it(`renders a div by default`, () => { - expect(document.querySelector("div")).not.toBeInTheDocument(); - const wrapper = render(); - expect(document.querySelector("div")).toBeInTheDocument(); - }); - - it(`renders a div wrap with style`, () => { - const wrapper = render( - - ); - expect(document.querySelector(`div[style]`).style.height).toEqual("100px"); - }); - - it(`renders a div wrap with className`, () => { - const wrapper = render(); - expect(document.querySelector("div.wrapper")).toBeInTheDocument(); - }); - - it(`calls the mountParcel prop when it mounts`, async () => { - const wrapper = render(); - await waitFor(() => expect(mountParcel).toHaveBeenCalled()); - }); - - it(`renders inside the append to`, async () => { - const appendTo = document.body.appendChild( - document.createElement("section") - ); - expect(document.querySelector("section div")).not.toBeInTheDocument(); - const wrapper = render(); - await waitFor(() => - expect(document.querySelector("section div")).toBeInTheDocument() - ); - }); - - it(`calls parcelDidMount prop when the parcel finishes mounting`, async () => { - const parcelDidMount = jest.fn(); - const wrapper = render( - - ); - - expect(parcelDidMount).not.toHaveBeenCalled(); - - await waitFor(() => expect(parcelDidMount).toHaveBeenCalled()); - }); - - it(`doesn't update the parcel a second or third time until previous parcel updates complete`, (done) => { - const wrapper = render(); - - let numParcelUpdateCalls = 0; - let firstParcelUpdateFinished = false; - let secondParcelUpdateFinished = false; - - parcel.update.mockImplementation(() => { - switch (++numParcelUpdateCalls) { - case 1: - return firstParcelUpdate(); - case 2: - return secondParcelUpdate(); - case 3: - return thirdParcelUpdate(); - default: - fail("Parcel update should only be called thrice"); - break; - } +const cases = [{ strictMode: false }, { strictMode: true }]; + +describe.each(cases)( + `, strict mode $strictMode`, + ({ strictMode }) => { + let config, + mountParcel = jest.fn(), + parcel, + props; + + beforeEach(() => { + configure({ reactStrictMode: strictMode }); + + config = { + bootstrap: jest.fn(), + mount: jest.fn(), + unmount: jest.fn(), + }; + + parcel = { + loadPromise: jest.fn(), + bootstrapPromise: jest.fn(), + mountPromise: Promise.resolve(), + unmountPromise: jest.fn(), + getStatus: jest.fn(), + unmount: jest.fn(), + update: jest.fn(), + }; + + mountParcel.mockReset(); + mountParcel.mockReturnValue(parcel); + + props = { mountParcel, config }; + jest.spyOn(console, "error").mockReturnValue(undefined); + }); + + afterAll(() => { + configure({ strictMode: false }); + }); + + it(`throws an error if you try to render the component without a config`, () => { + expect(() => { + render(); + }).toThrow(); + }); + + it(`renders a div by default`, () => { + expect(document.querySelector("div")).not.toBeInTheDocument(); + const wrapper = render(); + expect(document.querySelector("div")).toBeInTheDocument(); + }); + + it(`renders a div wrap with style`, () => { + const wrapper = render( + + ); + expect(document.querySelector(`div[style]`).style.height).toEqual( + "100px" + ); + }); + + it(`renders a div wrap with className`, () => { + const wrapper = render(); + expect(document.querySelector("div.wrapper")).toBeInTheDocument(); + }); + + it(`calls the mountParcel prop when it mounts`, async () => { + const wrapper = render(); + await waitFor(() => expect(mountParcel).toHaveBeenCalled()); + }); + + it(`renders inside the append to`, async () => { + const appendTo = document.body.appendChild( + document.createElement("section") + ); + expect(document.querySelector("section div")).not.toBeInTheDocument(); + const wrapper = render(); + await waitFor(() => + expect(document.querySelector("section div")).toBeInTheDocument() + ); + }); + + it(`calls parcelDidMount prop when the parcel finishes mounting`, async () => { + const parcelDidMount = jest.fn(); + const wrapper = render( + + ); + + expect(parcelDidMount).not.toHaveBeenCalled(); + + await waitFor(() => expect(parcelDidMount).toHaveBeenCalled()); }); - function firstParcelUpdate() { - return new Promise((resolve) => { - /* Don't resolve this promise for a while to make sure that the second update - * Doesn't start until the first finishes - */ - setTimeout(() => { - firstParcelUpdateFinished = true; - resolve(); - }, 100); + it(`doesn't update the parcel a second or third time until previous parcel updates complete`, (done) => { + const wrapper = render(); + + let numParcelUpdateCalls = 0; + let firstParcelUpdateFinished = false; + let secondParcelUpdateFinished = false; + + parcel.update.mockImplementation(() => { + switch (++numParcelUpdateCalls) { + case 1: + return firstParcelUpdate(); + case 2: + return secondParcelUpdate(); + case 3: + return thirdParcelUpdate(); + default: + fail("Parcel update should only be called thrice"); + break; + } }); - } - function secondParcelUpdate() { - return new Promise((resolve) => { - setTimeout(() => { + function firstParcelUpdate() { + return new Promise((resolve) => { + /* Don't resolve this promise for a while to make sure that the second update + * Doesn't start until the first finishes + */ + setTimeout(() => { + firstParcelUpdateFinished = true; + resolve(); + }, 100); + }); + } + + function secondParcelUpdate() { + return new Promise((resolve) => { + setTimeout(() => { + expect(firstParcelUpdateFinished).toBe(true); + secondParcelUpdateFinished = true; + resolve(); + }, 100); + }); + } + + function thirdParcelUpdate() { + return Promise.resolve().then(() => { expect(firstParcelUpdateFinished).toBe(true); - secondParcelUpdateFinished = true; - resolve(); - }, 100); - }); - } + expect(secondParcelUpdateFinished).toBe(true); + done(); + }); + } - function thirdParcelUpdate() { - return Promise.resolve().then(() => { - expect(firstParcelUpdateFinished).toBe(true); - expect(secondParcelUpdateFinished).toBe(true); - done(); - }); - } - - function triggerComponentDidUpdate() { - wrapper.rerender(); - } - - // not once - triggerComponentDidUpdate(); - - // not twice - triggerComponentDidUpdate(); - - // but thrice! - triggerComponentDidUpdate(); - }); - - it(`calls mountParcel with all the React props`, async () => { - const wrapper = render(); - // We need to wait for a microtask to finish before the Parcel component will have called mountParcel - await waitFor(() => expect(mountParcel).toHaveBeenCalled()); - const parcelProps = mountParcel.mock.calls[0][1]; - expect(parcelProps.domElement).toBeInstanceOf(HTMLDivElement); - }); - - it(`lets you not pass in a mountParcel prop if the SingleSpaContext is set with one (React <18)`, async () => { - // this creates the SingleSpaContext - singleSpaReact({ - React, - ReactDOM, - rootComponent() { - return null; - }, + function triggerComponentDidUpdate() { + wrapper.rerender(); + } + + // not once + triggerComponentDidUpdate(); + + // not twice + triggerComponentDidUpdate(); + + // but thrice! + triggerComponentDidUpdate(); }); - render( - - - - ); - - await waitFor(() => expect(mountParcel).toHaveBeenCalled()); - }); - - it(`lets you not pass in a mountParcel prop if the SingleSpaContext is set with one (React >=18)`, async () => { - // this creates the SingleSpaContext - singleSpaReact({ - React, - ReactDOMClient, - rootComponent() { - return null; - }, + it(`calls mountParcel with all the React props`, async () => { + const wrapper = render(); + // We need to wait for a microtask to finish before the Parcel component will have called mountParcel + await waitFor(() => expect(mountParcel).toHaveBeenCalled()); + const parcelProps = mountParcel.mock.calls[0][1]; + expect(parcelProps.domElement).toBeInstanceOf(HTMLDivElement); }); - const wrapper = render( - - - - ); + it(`lets you not pass in a mountParcel prop if the SingleSpaContext is set with one (React <18)`, async () => { + // this creates the SingleSpaContext + singleSpaReact({ + React, + ReactDOM, + rootComponent() { + return null; + }, + }); + + render( + + + + ); + + await waitFor(() => expect(mountParcel).toHaveBeenCalled()); + }); - await waitFor(() => expect(mountParcel).toHaveBeenCalled()); - }); -}); + it(`lets you not pass in a mountParcel prop if the SingleSpaContext is set with one (React >=18)`, async () => { + // this creates the SingleSpaContext + singleSpaReact({ + React, + ReactDOMClient, + rootComponent() { + return null; + }, + }); + + const wrapper = render( + + + + ); + + await waitFor(() => expect(mountParcel).toHaveBeenCalled()); + }); + } +);