diff --git a/package.json b/package.json index 4bc3c38ce6770..7e778f0e0527d 100644 --- a/package.json +++ b/package.json @@ -29,11 +29,6 @@ "nop": "exit 0" }, "private": true, - "pnpm": { - "overrides": { - "jsdom@^20.0.3>nwsapi@^2": "2.2.9" - } - }, "devDependencies": { "@gravitational/build": "workspace:*", "@ianvs/prettier-plugin-sort-imports": "^4.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8439a8ea302d..393b7d7c633f7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,9 +4,6 @@ settings: autoInstallPeers: false excludeLinksFromLockfile: false -overrides: - jsdom@^20.0.3>nwsapi@^2: 2.2.9 - pnpmfileChecksum: sha256-UhbfH9wqbTOi0Lx+Gm0eQ8EkqLSQxYCWXAFDAbl28uo= importers: @@ -278,8 +275,8 @@ importers: specifier: ^16.3.0 version: 16.3.0 jest-environment-jsdom: - specifier: ^29.7.0 - version: 29.7.0 + specifier: ^30.0.4 + version: 30.0.4 jest-fail-on-console: specifier: ^3.3.1 version: 3.3.1 @@ -1887,6 +1884,16 @@ packages: resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/environment-jsdom-abstract@30.0.4': + resolution: {integrity: sha512-pUKfqgr5Nki9kZ/3iV+ubDsvtPq0a0oNL6zqkKLM1tPQI8FBJeuWskvW1kzc5pOvqlgpzumYZveJ4bxhANY0hg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + jsdom: '*' + peerDependenciesMeta: + canvas: + optional: true + '@jest/environment@29.7.0': resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2886,9 +2893,6 @@ packages: '@types/jest@30.0.0': resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==} - '@types/jsdom@20.0.1': - resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} - '@types/jsdom@21.1.7': resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==} @@ -3215,10 +3219,6 @@ packages: '@xterm/xterm@5.5.0': resolution: {integrity: sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==} - abab@2.0.6: - resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} - deprecated: Use your platform's native atob() and btoa() methods instead - abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -3229,9 +3229,6 @@ packages: ace-builds@1.43.0: resolution: {integrity: sha512-iBkvY7owAPCquKCenPCEl4YVDOo9YPRfAZbOuzGcyJlMYhiA5aIEjFPZsYZvX1ZQ1Rq4cfYRhJjixSYcpDPOoQ==} - acorn-globals@7.0.1: - resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} - acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -3242,10 +3239,6 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} - engines: {node: '>=0.4.0'} - acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} @@ -3910,16 +3903,6 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} - cssom@0.3.8: - resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} - - cssom@0.5.0: - resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} - - cssstyle@2.3.0: - resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} - engines: {node: '>=8'} - cssstyle@4.3.1: resolution: {integrity: sha512-ZgW+Jgdd7i52AaLYCriF8Mxqft0gD/R9i9wi6RWBhs1pqdPEzPjym7rvRKi397WmQFf3SlyUsszhw+VVCbx79Q==} engines: {node: '>=18'} @@ -3986,10 +3969,6 @@ packages: resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} engines: {node: '>=12'} - data-urls@3.0.2: - resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} - engines: {node: '>=12'} - data-urls@5.0.0: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} @@ -4156,11 +4135,6 @@ packages: domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - domexception@4.0.0: - resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} - engines: {node: '>=12'} - deprecated: Use your platform's native DOMException instead - domhandler@2.4.2: resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==} @@ -4329,11 +4303,6 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - escodegen@2.1.0: - resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} - engines: {node: '>=6.0'} - hasBin: true - eslint-plugin-jest-dom@5.5.0: resolution: {integrity: sha512-CRlXfchTr7EgC3tDI7MGHY6QjdJU5Vv2RPaeeGtkXUHnKZf04kgzMPIJUXt4qKCvYWVVIEo9ut9Oq1vgXAykEA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6', yarn: '>=1'} @@ -4825,10 +4794,6 @@ packages: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} - html-encoding-sniffer@3.0.0: - resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} - engines: {node: '>=12'} - html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} @@ -5274,11 +5239,11 @@ packages: resolution: {integrity: sha512-ZFRsTpe5FUWFQ9cWTMguCaiA6kkW5whccPy9JjD1ezxh+mJeqmz8naL8Fl/oSbNJv3rgB0x87WBIkA5CObIUZQ==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-environment-jsdom@29.7.0: - resolution: {integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-environment-jsdom@30.0.4: + resolution: {integrity: sha512-9WmS3oyCLFgs6DUJSoMpVb+AbH62Y2Xecw3XClbRgj6/Z+VjNeSLjrhBgVvTZ40njZTWeDHv8unp+6M/z8ADDg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - canvas: ^2.5.0 + canvas: ^3.0.0 peerDependenciesMeta: canvas: optional: true @@ -5505,15 +5470,6 @@ packages: resolution: {integrity: sha512-8BAsnuoO4DLGTf7LDbSm8fcx5CUHSv4h+bdUbwyt6rMYAXWjeHLRx9f8sYiSxoOTXy3S1e06pe87KER39o1ckA==} engines: {node: '>=14'} - jsdom@20.0.3: - resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} - engines: {node: '>=14'} - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true - jsdom@26.1.0: resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==} engines: {node: '>=18'} @@ -5929,9 +5885,6 @@ packages: nwsapi@2.2.20: resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==} - nwsapi@2.2.9: - resolution: {integrity: sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==} - nyc@15.1.0: resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==} engines: {node: '>=8.9'} @@ -6914,10 +6867,6 @@ packages: resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} engines: {node: '>=16'} - tr46@3.0.0: - resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} - engines: {node: '>=12'} - tr46@5.1.0: resolution: {integrity: sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==} engines: {node: '>=18'} @@ -7202,10 +7151,6 @@ packages: w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} - w3c-xmlserializer@4.0.0: - resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} - engines: {node: '>=14'} - w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} @@ -7233,10 +7178,6 @@ packages: webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - whatwg-encoding@2.0.0: - resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} - engines: {node: '>=12'} - whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} @@ -7244,18 +7185,10 @@ packages: whatwg-fetch@3.6.20: resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} - whatwg-mimetype@3.0.0: - resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} - engines: {node: '>=12'} - whatwg-mimetype@4.0.0: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - whatwg-url@11.0.0: - resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} - engines: {node: '>=12'} - whatwg-url@14.2.0: resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} engines: {node: '>=18'} @@ -7347,10 +7280,6 @@ packages: resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==} engines: {node: '>=12'} - xml-name-validator@4.0.0: - resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} - engines: {node: '>=12'} - xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} @@ -9068,6 +8997,17 @@ snapshots: '@jest/diff-sequences@30.0.1': {} + '@jest/environment-jsdom-abstract@30.0.4(jsdom@26.1.0)': + dependencies: + '@jest/environment': 30.0.4 + '@jest/fake-timers': 30.0.4 + '@jest/types': 30.0.1 + '@types/jsdom': 21.1.7 + '@types/node': 22.15.34 + jest-mock: 30.0.2 + jest-util: 30.0.2 + jsdom: 26.1.0 + '@jest/environment@29.7.0': dependencies: '@jest/fake-timers': 29.7.0 @@ -10330,12 +10270,6 @@ snapshots: expect: 30.0.4 pretty-format: 30.0.2 - '@types/jsdom@20.0.1': - dependencies: - '@types/node': 22.15.34 - '@types/tough-cookie': 4.0.5 - parse5: 7.3.0 - '@types/jsdom@21.1.7': dependencies: '@types/node': 22.15.34 @@ -10673,19 +10607,12 @@ snapshots: '@xterm/xterm@5.5.0': {} - abab@2.0.6: {} - abbrev@1.1.1: {} abbrev@3.0.0: {} ace-builds@1.43.0: {} - acorn-globals@7.0.1: - dependencies: - acorn: 8.15.0 - acorn-walk: 8.3.4 - acorn-import-attributes@1.9.5(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -10694,10 +10621,6 @@ snapshots: dependencies: acorn: 8.15.0 - acorn-walk@8.3.4: - dependencies: - acorn: 8.15.0 - acorn@8.15.0: {} agent-base@6.0.2: @@ -11584,14 +11507,6 @@ snapshots: dependencies: css-tree: 2.2.1 - cssom@0.3.8: {} - - cssom@0.5.0: {} - - cssstyle@2.3.0: - dependencies: - cssom: 0.3.8 - cssstyle@4.3.1: dependencies: '@asamuzakjp/css-color': 3.1.7 @@ -11659,12 +11574,6 @@ snapshots: dependencies: d3-array: 3.2.4 - data-urls@3.0.2: - dependencies: - abab: 2.0.6 - whatwg-mimetype: 3.0.0 - whatwg-url: 11.0.0 - data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 @@ -11833,10 +11742,6 @@ snapshots: domelementtype@2.3.0: {} - domexception@4.0.0: - dependencies: - webidl-conversions: 7.0.0 - domhandler@2.4.2: dependencies: domelementtype: 1.3.1 @@ -12106,14 +12011,6 @@ snapshots: escape-string-regexp@4.0.0: {} - escodegen@2.1.0: - dependencies: - esprima: 4.0.1 - estraverse: 5.3.0 - esutils: 2.0.3 - optionalDependencies: - source-map: 0.6.1 - eslint-plugin-jest-dom@5.5.0(@testing-library/dom@10.1.0)(eslint@9.30.0): dependencies: '@babel/runtime': 7.27.1 @@ -12672,10 +12569,6 @@ snapshots: dependencies: lru-cache: 6.0.0 - html-encoding-sniffer@3.0.0: - dependencies: - whatwg-encoding: 2.0.0 - html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 @@ -13266,16 +13159,13 @@ snapshots: jest-util: 30.0.2 pretty-format: 30.0.2 - jest-environment-jsdom@29.7.0: + jest-environment-jsdom@30.0.4: dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/jsdom': 20.0.1 + '@jest/environment': 30.0.4 + '@jest/environment-jsdom-abstract': 30.0.4(jsdom@26.1.0) + '@types/jsdom': 21.1.7 '@types/node': 22.15.34 - jest-mock: 29.7.0 - jest-util: 29.7.0 - jsdom: 20.0.3 + jsdom: 26.1.0 transitivePeerDependencies: - bufferutil - supports-color @@ -13792,39 +13682,6 @@ snapshots: bezier-easing: 2.1.0 css-mediaquery: 0.1.2 - jsdom@20.0.3: - dependencies: - abab: 2.0.6 - acorn: 8.15.0 - acorn-globals: 7.0.1 - cssom: 0.5.0 - cssstyle: 2.3.0 - data-urls: 3.0.2 - decimal.js: 10.5.0 - domexception: 4.0.0 - escodegen: 2.1.0 - form-data: 4.0.2 - html-encoding-sniffer: 3.0.0 - http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 - is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.9 - parse5: 7.3.0 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 4.1.4 - w3c-xmlserializer: 4.0.0 - webidl-conversions: 7.0.0 - whatwg-encoding: 2.0.0 - whatwg-mimetype: 3.0.0 - whatwg-url: 11.0.0 - ws: 8.18.2 - xml-name-validator: 4.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - jsdom@26.1.0: dependencies: cssstyle: 4.3.1 @@ -14250,8 +14107,6 @@ snapshots: nwsapi@2.2.20: {} - nwsapi@2.2.9: {} - nyc@15.1.0: dependencies: '@istanbuljs/load-nyc-config': 1.1.0 @@ -15415,10 +15270,6 @@ snapshots: dependencies: tldts: 6.1.86 - tr46@3.0.0: - dependencies: - punycode: 2.3.1 - tr46@5.1.0: dependencies: punycode: 2.3.1 @@ -15683,10 +15534,6 @@ snapshots: w3c-keyname@2.2.8: {} - w3c-xmlserializer@4.0.0: - dependencies: - xml-name-validator: 4.0.0 - w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 @@ -15721,25 +15568,14 @@ snapshots: webpack-virtual-modules@0.6.2: {} - whatwg-encoding@2.0.0: - dependencies: - iconv-lite: 0.6.3 - whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 whatwg-fetch@3.6.20: {} - whatwg-mimetype@3.0.0: {} - whatwg-mimetype@4.0.0: {} - whatwg-url@11.0.0: - dependencies: - tr46: 3.0.0 - webidl-conversions: 7.0.0 - whatwg-url@14.2.0: dependencies: tr46: 5.1.0 @@ -15863,8 +15699,6 @@ snapshots: xdg-basedir@5.1.0: {} - xml-name-validator@4.0.0: {} - xml-name-validator@5.0.0: {} xml@1.0.1: {} diff --git a/web/packages/build/jest/jest-environment-patched-jsdom.js b/web/packages/build/jest/jest-environment-patched-jsdom.js index cf8505da1c6c7..ec5075d973ca7 100644 --- a/web/packages/build/jest/jest-environment-patched-jsdom.js +++ b/web/packages/build/jest/jest-environment-patched-jsdom.js @@ -25,9 +25,7 @@ export default class PatchedJSDOMEnvironment extends JSDOMEnvironment { // TODO(sshah): Remove this once JSDOM provides structuredClone. // https://github.com/jsdom/jsdom/issues/3363 if (!global.structuredClone) { - global.structuredClone = val => { - return JSON.parse(JSON.stringify(val)); - }; + global.structuredClone = structuredClone; } // TODO(gzdunek): Remove this once JSDOM provides scrollIntoView. @@ -59,27 +57,6 @@ export default class PatchedJSDOMEnvironment extends JSDOMEnvironment { if (!global.TransformStream) { global.TransformStream = TransformStream; } - // TODO(gzdunek): JSDOM doesn't support AbortSignal.any(). - // Overwriting only this function doesn't help much, something between - // AbortSignal and AbortController is missing. - if (!global.AbortSignal.any) { - global.AbortSignal = AbortSignal; - global.AbortController = AbortController; - } - // TODO(gzdunek): Remove when JSDOM supports Set.prototype.difference. - // After the update to Node.js 22, we can replace the implementation with - // global.Set.prototype.difference = Set.prototype.difference. - if (!global.Set.difference) { - global.Set.prototype.difference = function (otherSet) { - const result = new Set(); - for (const value of this) { - if (!otherSet.has(value)) { - result.add(value); - } - } - return result; - }; - } // If a test actually depends on a working ResizeObserver implementation, call // mockResizeObserver provided by jsdom-testing-mocks. diff --git a/web/packages/build/package.json b/web/packages/build/package.json index 30f733ddac525..8e96abe0ef42a 100644 --- a/web/packages/build/package.json +++ b/web/packages/build/package.json @@ -28,7 +28,7 @@ "eslint-plugin-testing-library": "7.4.0", "eslint-plugin-unused-imports": "^4.1.4", "globals": "^16.3.0", - "jest-environment-jsdom": "^29.7.0", + "jest-environment-jsdom": "^30.0.4", "jest-fail-on-console": "^3.3.1", "jsdom": "^26.1.0", "rollup-plugin-visualizer": "^6.0.3", diff --git a/web/packages/design/src/Modal/Modal.test.tsx b/web/packages/design/src/Modal/Modal.test.tsx index 8ffee5e28e7d5..6e1c86eef2ce2 100644 --- a/web/packages/design/src/Modal/Modal.test.tsx +++ b/web/packages/design/src/Modal/Modal.test.tsx @@ -138,7 +138,7 @@ test('respects backdropProps prop invisible', () => { }); expect(screen.getByTestId('backdrop')).toHaveStyle({ - 'background-color': 'transparent', + 'background-color': 'rgba(0, 0, 0, 0)', }); }); diff --git a/web/packages/teleport/src/AppLauncher/AppLauncher.test.tsx b/web/packages/teleport/src/AppLauncher/AppLauncher.test.tsx index 3280ef5c5f4a9..f1ae78e637fcf 100644 --- a/web/packages/teleport/src/AppLauncher/AppLauncher.test.tsx +++ b/web/packages/teleport/src/AppLauncher/AppLauncher.test.tsx @@ -76,9 +76,6 @@ const launcherPathTestCases: { ]; describe('app launcher path is properly formed', () => { - const realLocation = window.location; - const assignMock = jest.fn(); - beforeEach(() => { global.fetch = jest.fn(() => Promise.resolve({})) as jest.Mock; jest.spyOn(api, 'get').mockResolvedValue({}); @@ -91,21 +88,11 @@ describe('app launcher path is properly formed', () => { subjectCookieValue: 'subject-cookie-value', fqdn: '', }); - - delete window.location; - window.location = { - ...realLocation, - replace: assignMock, - } as unknown as string & Location; }); - afterEach(() => { - window.location = { - ...realLocation, - replace: assignMock, - } as unknown as string & Location; - assignMock.mockClear(); - }); + const windowLocation = { + replace: jest.fn(), + }; test.each(launcherPathTestCases)( '$name', @@ -113,13 +100,13 @@ describe('app launcher path is properly formed', () => { render( - + ); await waitFor(() => - expect(window.location.replace).toHaveBeenCalledWith( + expect(windowLocation.replace).toHaveBeenCalledWith( `https://grafana.localhost/${expectedPath}` ) ); @@ -259,27 +246,9 @@ const appSessionTestCases: { ]; describe('fqdn is matched', () => { - const realLocation = window.location; - const assignMock = jest.fn(); - beforeEach(() => { - global.fetch = jest.fn(() => Promise.resolve({})) as jest.Mock; jest.spyOn(api, 'get').mockResolvedValue({}); jest.spyOn(api, 'post').mockResolvedValue({}); - - delete window.location; - window.location = { - ...realLocation, - replace: assignMock, - } as unknown as string & Location; - }); - - afterEach(() => { - window.location = { - ...realLocation, - replace: assignMock, - } as unknown as string & Location; - assignMock.mockClear(); }); test.each(appSessionTestCases)( @@ -295,11 +264,14 @@ describe('fqdn is matched', () => { fqdn: returnedFqdn, }); jest.spyOn(service, 'createAppSession'); + const windowLocation = { + replace: jest.fn(), + }; render( - + ); @@ -313,7 +285,7 @@ describe('fqdn is matched', () => { }); }); - await waitFor(() => expect(window.location.replace).toHaveBeenCalled()); + await waitFor(() => expect(windowLocation.replace).toHaveBeenCalled()); expect(screen.queryByText(/access denied/i)).not.toBeInTheDocument(); } ); @@ -322,6 +294,9 @@ describe('fqdn is matched', () => { jest.spyOn(service, 'getAppDetails').mockResolvedValue({ fqdn: 'different.fqdn', }); + const windowLocation = { + replace: jest.fn(), + }; render( { )} > - + ); @@ -341,13 +316,16 @@ describe('fqdn is matched', () => { /failed to match applications with FQDN "test-app.test.teleport:443"/i ) ).toBeInTheDocument(); - expect(window.location.replace).not.toHaveBeenCalled(); + expect(windowLocation.replace).not.toHaveBeenCalled(); }); test('invalid URL when constructing a new URL with a malformed FQDN', async () => { jest.spyOn(service, 'getAppDetails').mockResolvedValue({ fqdn: 'invalid.fqdn:3080:3090', }); + const windowLocation = { + replace: jest.fn(), + }; render( { )} > - + ); await screen.findByText(/access denied/i); expect(screen.getByText(/Failed to parse URL:/i)).toBeInTheDocument(); - expect(window.location.replace).not.toHaveBeenCalled(); + expect(windowLocation.replace).not.toHaveBeenCalled(); }); }); diff --git a/web/packages/teleport/src/AppLauncher/AppLauncher.tsx b/web/packages/teleport/src/AppLauncher/AppLauncher.tsx index 08b89a4dd416a..1b47098585ab9 100644 --- a/web/packages/teleport/src/AppLauncher/AppLauncher.tsx +++ b/web/packages/teleport/src/AppLauncher/AppLauncher.tsx @@ -29,7 +29,12 @@ import { useMfa } from 'teleport/lib/useMfa'; import service from 'teleport/services/apps'; import { MfaChallengeScope } from 'teleport/services/auth/auth'; -export function AppLauncher() { +export function AppLauncher({ + windowLocation = window.location, +}: { + /** Allows overwriting `window.location` in tests. */ + windowLocation?: Pick; +}) { const { attempt, setAttempt } = useAttempt('processing'); const pathParams = useParams(); @@ -100,13 +105,14 @@ export function AppLauncher() { // Let the target app know of a new auth exchange. const stateToken = queryParams.get('state'); if (!stateToken) { - initiateNewAuthExchange({ + const url = getNewAuthExchangeUrl({ fqdn, port, path, params, requiredApps, }); + windowLocation.replace(url.toString()); return; } @@ -139,7 +145,7 @@ export function AppLauncher() { // This will load an empty HTML with the inline JS containing // logic to finish the auth exchange. - window.location.replace(url.toString()); + windowLocation.replace(url.toString()); } catch (err) { let statusText = 'Something went wrong'; @@ -217,8 +223,7 @@ function getXTeleportAuthUrl({ fqdn, port }: { fqdn: string; port: string }) { } } -// initiateNewAuthExchange is the first step to gaining access to an -// application. +// Returns the URL to gain access to an application. // // It can be initiated in two ways: // 1) user clicked our "launch" app button from the resource list @@ -226,7 +231,7 @@ function getXTeleportAuthUrl({ fqdn, port }: { fqdn: string; port: string }) { // 2) user hits the app endpoint directly (eg: cliking on a // bookmarked URL), in which the server will redirect the user // to this launcher. -function initiateNewAuthExchange({ +function getNewAuthExchangeUrl({ fqdn, port, params, @@ -274,7 +279,7 @@ function initiateNewAuthExchange({ url.searchParams.set('arn', params.arn); } - window.location.replace(url.toString()); + return url; } function throwFailedToParseUrlError(err: TypeError) { diff --git a/web/packages/teleport/src/lib/util.test.ts b/web/packages/teleport/src/lib/util.test.ts index 8e85a268f655f..2c309f379c099 100644 --- a/web/packages/teleport/src/lib/util.test.ts +++ b/web/packages/teleport/src/lib/util.test.ts @@ -18,30 +18,17 @@ import { arrayStrDiff, compareByString, generateTshLoginCommand } from './util'; -let windowSpy; - -beforeEach(() => { - windowSpy = jest.spyOn(window, 'window', 'get'); -}); - -afterEach(() => { - windowSpy.mockRestore(); -}); - test('with all params defined', () => { - windowSpy.mockImplementation(() => ({ - location: { - hostname: 'my-cluster', - port: '1234', - }, - })); - expect( generateTshLoginCommand({ accessRequestId: 'ar-1234', username: 'llama', authType: 'local', clusterId: 'cluster-1234', + windowLocation: { + hostname: 'my-cluster', + port: '1234', + }, }) ).toBe( 'tsh login --proxy=my-cluster:1234 --auth=local --user=llama cluster-1234 --request-id=ar-1234' @@ -49,17 +36,12 @@ test('with all params defined', () => { }); test('no port and access request id', () => { - windowSpy.mockImplementation(() => ({ - location: { - hostname: 'my-cluster', - }, - })); - expect( generateTshLoginCommand({ username: 'llama', authType: 'sso', clusterId: 'cluster-1234', + windowLocation: { hostname: 'my-cluster' }, }) ).toBe('tsh login --proxy=my-cluster:443 cluster-1234'); }); diff --git a/web/packages/teleport/src/lib/util.ts b/web/packages/teleport/src/lib/util.ts index 38dfe13bd8ca7..390d15264ab54 100644 --- a/web/packages/teleport/src/lib/util.ts +++ b/web/packages/teleport/src/lib/util.ts @@ -29,20 +29,25 @@ export const openNewTab = (url: string) => { document.body.removeChild(element); }; -export type TshLoginCommand = { - authType: AuthType; - clusterId?: string; - username: string; - accessRequestId?: string; -}; - export function generateTshLoginCommand({ authType, clusterId = '', username, accessRequestId = '', -}: TshLoginCommand) { - const { hostname, port } = window.location; + windowLocation = window.location, +}: { + authType: AuthType; + clusterId?: string; + username: string; + accessRequestId?: string; + /** Allows overwriting `window.location` in tests. */ + windowLocation?: { + hostname: string; + /** When empty, the default HTTPS port (443) is used. */ + port?: string; + }; +}) { + const { hostname, port } = windowLocation; const host = `${hostname}:${port || '443'}`; const requestId = accessRequestId ? ` --request-id=${accessRequestId}` : '';