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}` : '';