diff --git a/CODEOWNERS b/CODEOWNERS index a74369bf8..0c33233b0 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,4 +1,4 @@ # Automatically request reviews for dependency updates -/package.json @esanuandra @beatrice-acasandrei @canova @kala-moz -/package-lock.json @esanuandra @beatrice-acasandrei @canova @kala-moz +/package.json @esanuandra @beatrice-acasandrei @kala-moz +/package-lock.json @esanuandra @beatrice-acasandrei @kala-moz diff --git a/eslint.config.mjs b/eslint.config.mjs index bb044cad0..4ff2f8773 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -82,6 +82,15 @@ export default defineConfig([ projectService: true, }, }, + + rules: { + // Allow intentionally-unused args to be marked with a leading underscore + // (e.g. interface methods that ignore a parameter). + '@typescript-eslint/no-unused-vars': [ + 'error', + { argsIgnorePattern: '^_' }, + ], + }, }, { // Typescript test files diff --git a/jest.config.ts b/jest.config.ts index 303137c53..914fac80e 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -18,7 +18,7 @@ const config: Config.InitialOptions = { testPathIgnorePatterns: ['/node_modules/', '/src/__tests__/utils/'], testEnvironment: './src/__tests__/utils/custom-environment', transform: { - '^.+\\.(t|j)sx?$': [ + '^.+\\.[cm]?[tj]sx?$': [ '@swc/jest', { jsc: { @@ -26,6 +26,17 @@ const config: Config.InitialOptions = { react: { runtime: 'automatic', }, + // react-router (ESM-only since v8) guards a dev-only HMR branch + // with `import.meta.hot`, which is a syntax error once swc + // transforms the module to CommonJS for jest. There is no HMR in + // tests, so compile the check away. + optimizer: { + globals: { + vars: { + 'import.meta.hot': 'undefined', + }, + }, + }, }, }, }, @@ -38,7 +49,7 @@ const config: Config.InitialOptions = { // dependencies of fetch-mock do! Hopefully this won't be needed in the future // when fetch-mock updates. transformIgnorePatterns: [ - '/node_modules/(?!(taskcluster-client-web|data-uri-to-buffer|fetch-blob|formdata-polyfill|fetch-mock|@fetch-mock/jest)/)', + '/node_modules/(?!(taskcluster-client-web|data-uri-to-buffer|fetch-blob|formdata-polyfill|fetch-mock|@fetch-mock/jest|react-router|cookie-es)/)', ], modulePaths: [], moduleNameMapper: { diff --git a/package-lock.json b/package-lock.json index 4b4a936bc..b9525acb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,21 +16,21 @@ "assert": "^2.1.0", "buffer": "^6.0.3", "crypto-browserify": "^3.12.1", - "dayjs": "^1.11.21", + "dayjs": "^1.11.23", "echarts": "^6.1.0", "express": "^5.2.1", "fast-kde": "^0.2.2", "format": "^0.2.2", - "json-e": "^4.8.2", + "json-e": "^4.8.4", "material-ui-popup-state": "^5.3.7", "moize": "^6.1.7", "notistack": "^3.0.2", "process": "^0.11.10", - "react": "^19.2.7", - "react-dom": "^19.2.7", + "react": "^19.2.8", + "react-dom": "^19.2.8", "react-redux": "^9.3.0", - "react-router": "^7.18.1", - "react-virtuoso": "^4.18.10", + "react-router": "^8.3.0", + "react-virtuoso": "^4.18.12", "stream-browserify": "^3.0.0", "taskcluster-client-web": "^87.1.3", "taskcluster-lib-scopes": "^11.0.0", @@ -47,35 +47,35 @@ "@eslint/js": "^9.39.5", "@fetch-mock/jest": "^0.2.20", "@jest/types": "^30.4.1", - "@swc/core": "^1.15.43", + "@swc/core": "^1.16.1", "@swc/jest": "^0.2.39", "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^6.9.1", + "@testing-library/jest-dom": "^6.10.0", "@testing-library/react": "^16.3.2", - "@testing-library/user-event": "^14.6.1", + "@testing-library/user-event": "^14.6.6", "@types/jest": "^30.0.0", "@types/jest-axe": "^3.5.9", "@types/material-ui": "^0.21.18", "@types/node": "^25.9.5", - "@types/react": "^19.2.17", - "@types/react-dom": "^19.2.3", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.5", "babel-loader": "^10.1.1", "babel-preset-jest": "^30.4.0", "case-sensitive-paths-webpack-plugin": "^2.4.0", "copy-webpack-plugin": "^13.0.1", - "core-js": "^3.49.0", + "core-js": "^3.50.0", "css-loader": "^7.1.4", "eslint": "^9.39.5", "eslint-config-prettier": "^10.1.8", "eslint-import-resolver-typescript": "^4.4.5", "eslint-plugin-import": "^2.32.0", - "eslint-plugin-jest": "^29.15.4", - "eslint-plugin-jest-dom": "^5.5.0", + "eslint-plugin-jest": "^29.16.1", + "eslint-plugin-jest-dom": "^5.10.1", "eslint-plugin-react": "^7.37.5", "eslint-plugin-testing-library": "^7.16.2", - "globals": "^17.7.0", + "globals": "^17.11.0", "history": "^5.3.0", - "html-webpack-plugin": "^5.6.7", + "html-webpack-plugin": "^5.6.8", "jest": "^30.4.2", "jest-axe": "^10.0.0", "jest-environment-jsdom": "^30.4.1", @@ -86,12 +86,12 @@ "react-refresh": "^0.18.0", "regenerator-runtime": "^0.14.1", "style-loader": "^4.0.0", - "ts-jest": "^29.4.11", + "ts-jest": "^29.4.12", "ts-loader": "^9.6.2", "ts-node": "^10.9.2", "typescript": "^5.9.3", - "typescript-eslint": "^8.62.1", - "webpack": "^5.108.4", + "typescript-eslint": "^8.67.0", + "webpack": "^5.109.2", "webpack-cli": "^6.0.1", "webpack-dev-server": "^5.2.6", "webpack-merge": "^6.0.1" @@ -3948,14 +3948,14 @@ "license": "MIT" }, "node_modules/@swc/core": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.43.tgz", - "integrity": "sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.16.1.tgz", + "integrity": "sha512-nUaeu91O5QZKrQdaDCHd402ogUIoNOOjpkZNq0UomWK0G6gDaGmLhvddF1/3BXf5O8aLyo6ZPY/aMDWvaJQ/hg==", "dev": true, "hasInstallScript": true, "dependencies": { "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.27" + "@swc/types": "^0.1.28" }, "engines": { "node": ">=10" @@ -3965,18 +3965,18 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.15.43", - "@swc/core-darwin-x64": "1.15.43", - "@swc/core-linux-arm-gnueabihf": "1.15.43", - "@swc/core-linux-arm64-gnu": "1.15.43", - "@swc/core-linux-arm64-musl": "1.15.43", - "@swc/core-linux-ppc64-gnu": "1.15.43", - "@swc/core-linux-s390x-gnu": "1.15.43", - "@swc/core-linux-x64-gnu": "1.15.43", - "@swc/core-linux-x64-musl": "1.15.43", - "@swc/core-win32-arm64-msvc": "1.15.43", - "@swc/core-win32-ia32-msvc": "1.15.43", - "@swc/core-win32-x64-msvc": "1.15.43" + "@swc/core-darwin-arm64": "1.16.1", + "@swc/core-darwin-x64": "1.16.1", + "@swc/core-linux-arm-gnueabihf": "1.16.1", + "@swc/core-linux-arm64-gnu": "1.16.1", + "@swc/core-linux-arm64-musl": "1.16.1", + "@swc/core-linux-ppc64-gnu": "1.16.1", + "@swc/core-linux-s390x-gnu": "1.16.1", + "@swc/core-linux-x64-gnu": "1.16.1", + "@swc/core-linux-x64-musl": "1.16.1", + "@swc/core-win32-arm64-msvc": "1.16.1", + "@swc/core-win32-ia32-msvc": "1.16.1", + "@swc/core-win32-x64-msvc": "1.16.1" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" @@ -3988,9 +3988,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.43.tgz", - "integrity": "sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.16.1.tgz", + "integrity": "sha512-zlJblJ8ncErD43lKdxjbUaUskJQf+LxiPXYcWXD8/8ZMV+7uuAT+CwjciLXpyZBd5Pq/S726bMpeeAwSeL1hhg==", "cpu": [ "arm64" ], @@ -4004,9 +4004,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.43.tgz", - "integrity": "sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.16.1.tgz", + "integrity": "sha512-IN0BmPWb0YAh/17mmlWB/HDBtTw2MfuW4hulf/tQAgTQBRH17l+z499bNJLK6LizSjqs0P7V+jU38Zj+vJC1DA==", "cpu": [ "x64" ], @@ -4020,9 +4020,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.43.tgz", - "integrity": "sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.16.1.tgz", + "integrity": "sha512-EYgrx2YOCQ2Twz2S793kqNjPkpvYVUPzzR95bIb7by+VQcyaai4lZZ2iz/tZvcFVKSNcN3/JTKwx+aBn2ZL52A==", "cpu": [ "arm" ], @@ -4036,9 +4036,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.43.tgz", - "integrity": "sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.16.1.tgz", + "integrity": "sha512-moyKm0YZlHdHohzm1YwgAyesqnE853rO0REMfJLFAova51wF9BNi+3ZW2PeS7Vqvn6HeJuepLpAHbBdZctxpHA==", "cpu": [ "arm64" ], @@ -4052,9 +4052,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.43.tgz", - "integrity": "sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.16.1.tgz", + "integrity": "sha512-kKGBO9wdapiSzuf5ZzZ2fYtlu1BNSYtIIUxvH1ir/gcelTOREEHGDCLTDFx/2Knf878nU11A40z7LxwasEFxqA==", "cpu": [ "arm64" ], @@ -4068,9 +4068,9 @@ } }, "node_modules/@swc/core-linux-ppc64-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.43.tgz", - "integrity": "sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.16.1.tgz", + "integrity": "sha512-nZ6qahtLxC3PM54cWOQZHxt4lTCF/3J4LIoWWzz6v7A+rLs8Dx54anYQf7mH3eIi8KlNpgKci/ie8ZSqFN8O7A==", "cpu": [ "ppc64" ], @@ -4084,9 +4084,9 @@ } }, "node_modules/@swc/core-linux-s390x-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.43.tgz", - "integrity": "sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.16.1.tgz", + "integrity": "sha512-4ji5PNzhYq193Z4/4xUaSoNJza6iCkDJSzhetrbB6KOYxsr+kxtQr8ePWhMJUiMt6JUWtXaZ1PYT8FhtED+nGA==", "cpu": [ "s390x" ], @@ -4100,9 +4100,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.43.tgz", - "integrity": "sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.16.1.tgz", + "integrity": "sha512-VJQxqrisHV+B394IgrOu8YsIIXZgffnf5tO+yc9Z/hoUpuZEvuQTjWwlnpZdpyD+0nx6LTD1/3k646JYm43yJA==", "cpu": [ "x64" ], @@ -4116,9 +4116,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.43.tgz", - "integrity": "sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.16.1.tgz", + "integrity": "sha512-r9oV1mwxxsIGcLV1IQ/tw76MW3doatKze1QFWuC+a7QqJUkhY/bKTSVk6NpKKUGm2LDsE33Va8VqSClfA7vSiQ==", "cpu": [ "x64" ], @@ -4132,9 +4132,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.43.tgz", - "integrity": "sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.16.1.tgz", + "integrity": "sha512-6huNRessoBLxWEqBm5zJXyCQ27TO7anvkdiuQ5MDO4CJni0nOXEqKtV9RllQ2TdyENKKsUMXVnIfW2hIXx/R5Q==", "cpu": [ "arm64" ], @@ -4148,9 +4148,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.43.tgz", - "integrity": "sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.16.1.tgz", + "integrity": "sha512-OVKJFUzphrGmsh+BGtcZDesx0YryV7/Yvy5XGgTqnrZfjnyfcr5uaqYQugCckdIlupc5Vs3XtDjRAj12z4ZPlw==", "cpu": [ "ia32" ], @@ -4164,9 +4164,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.43.tgz", - "integrity": "sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.16.1.tgz", + "integrity": "sha512-Bt+VIhWYCGk4urklnkkteLUOeLv1VxigwTCeB/xC6rBZxY6IIKdDwCJf6on3E3SUGsIqmQS6QqtuJQc1VxF4Aw==", "cpu": [ "x64" ], @@ -4204,9 +4204,9 @@ } }, "node_modules/@swc/types": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.27.tgz", - "integrity": "sha512-K6h3iUlqeM946U4sXFYeahefR1YBbXJvko+hv8WS8/0BNJ4OHiHRywMnQUJCqkR7Y9+hqQ1TvEpiKqUhz7NEFg==", + "version": "0.1.28", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.28.tgz", + "integrity": "sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw==", "dev": true, "dependencies": { "@swc/counter": "^0.1.3" @@ -4264,9 +4264,10 @@ "dev": true }, "node_modules/@testing-library/jest-dom": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", - "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.10.0.tgz", + "integrity": "sha512-HQwu0KaB2zyT0iLzBL+8CLyZDL3KlZlZJ+2iyc9uCUnlJVskJU/UlPuVCyIPhtukjPQdT2QNoR5nCP5FqTmmDQ==", + "deprecated": "Incorrect minor release with breaking changes (Node >=22 and required @testing-library/dom peer). Use 6.9.1 for the 6.x line, or upgrade to 7.0.0.", "dev": true, "dependencies": { "@adobe/css-tools": "^4.4.0", @@ -4277,9 +4278,12 @@ "redent": "^3.0.0" }, "engines": { - "node": ">=14", + "node": ">=22", "npm": ">=6", "yarn": ">=1" + }, + "peerDependencies": { + "@testing-library/dom": ">=10 <11" } }, "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { @@ -4317,11 +4321,10 @@ } }, "node_modules/@testing-library/user-event": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", - "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "version": "14.6.6", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.6.tgz", + "integrity": "sha512-Jbs9FpkkIDw8FgSc6kOVsOv8JuuqGAL7J4X1oot77JxAoDlkNn2GRkd0aYRVuQ+pVQAiHWVkE4rX/dkF5fBiCw==", "dev": true, - "license": "MIT", "engines": { "node": ">=12", "npm": ">=6" @@ -4695,9 +4698,9 @@ "dev": true }, "node_modules/@types/react": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", - "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", "dependencies": { "csstype": "^3.2.2" } @@ -4712,9 +4715,9 @@ } }, "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-fMPwH9v7r/pp43yUd2/Mbiex5KouJwwR3dzHkhLREUC6764VyDsqxhAxv6OFEYR1RhjOyD1naqba8ECDBe7ZQg==", "dev": true, "peerDependencies": { "@types/react": "^19.2.0" @@ -4826,16 +4829,16 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.1.tgz", - "integrity": "sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.67.0.tgz", + "integrity": "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.62.1", - "@typescript-eslint/type-utils": "8.62.1", - "@typescript-eslint/utils": "8.62.1", - "@typescript-eslint/visitor-keys": "8.62.1", + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/type-utils": "8.67.0", + "@typescript-eslint/utils": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -4848,7 +4851,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.62.1", + "@typescript-eslint/parser": "^8.67.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -4864,15 +4867,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.1.tgz", - "integrity": "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.67.0.tgz", + "integrity": "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.62.1", - "@typescript-eslint/types": "8.62.1", - "@typescript-eslint/typescript-estree": "8.62.1", - "@typescript-eslint/visitor-keys": "8.62.1", + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", "debug": "^4.4.3" }, "engines": { @@ -4888,13 +4891,13 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.1.tgz", - "integrity": "sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.67.0.tgz", + "integrity": "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==", "dev": true, "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.62.1", - "@typescript-eslint/types": "^8.62.1", + "@typescript-eslint/tsconfig-utils": "^8.67.0", + "@typescript-eslint/types": "^8.67.0", "debug": "^4.4.3" }, "engines": { @@ -4909,13 +4912,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.1.tgz", - "integrity": "sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz", + "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.62.1", - "@typescript-eslint/visitor-keys": "8.62.1" + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4926,9 +4929,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.1.tgz", - "integrity": "sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.67.0.tgz", + "integrity": "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4942,14 +4945,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.1.tgz", - "integrity": "sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.67.0.tgz", + "integrity": "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.62.1", - "@typescript-eslint/typescript-estree": "8.62.1", - "@typescript-eslint/utils": "8.62.1", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/utils": "8.67.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -4966,9 +4969,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.1.tgz", - "integrity": "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", + "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4979,15 +4982,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.1.tgz", - "integrity": "sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz", + "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==", "dev": true, "dependencies": { - "@typescript-eslint/project-service": "8.62.1", - "@typescript-eslint/tsconfig-utils": "8.62.1", - "@typescript-eslint/types": "8.62.1", - "@typescript-eslint/visitor-keys": "8.62.1", + "@typescript-eslint/project-service": "8.67.0", + "@typescript-eslint/tsconfig-utils": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -5015,24 +5018,24 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", - "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, "dependencies": { - "brace-expansion": "^5.0.5" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -5042,15 +5045,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.1.tgz", - "integrity": "sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz", + "integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.62.1", - "@typescript-eslint/types": "8.62.1", - "@typescript-eslint/typescript-estree": "8.62.1" + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5065,12 +5068,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.1.tgz", - "integrity": "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz", + "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/types": "8.67.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -5616,18 +5619,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", - "dev": true, - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "acorn": "^8.14.0" - } - }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -7098,6 +7089,11 @@ "node": ">= 0.6" } }, + "node_modules/cookie-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz", + "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==" + }, "node_modules/cookie-signature": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", @@ -7131,11 +7127,14 @@ } }, "node_modules/core-js": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", - "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.50.0.tgz", + "integrity": "sha512-BRWgOLKkFeCgRudR6zrs8p9XJZcE14grzKMMssoYrk6krtuEZ7MTKPIY5RzOnqsEKIR9kst7wNzphttraT+Yqw==", "dev": true, "hasInstallScript": true, + "engines": { + "node": "*" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -7440,9 +7439,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.21", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", - "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==" + "version": "1.11.23", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.23.tgz", + "integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==" }, "node_modules/debug": { "version": "4.4.3", @@ -7860,9 +7859,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.23.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.23.0.tgz", - "integrity": "sha512-yJN/BOOLxcOW2aQgeif9mSnaUB8KtvmMMp56oA1kx1CRfBKbhZm2pJ+NBY+3eOboHxix8lfjWpHE0Ei5U8RbSA==", + "version": "5.24.5", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", + "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -8351,9 +8350,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "29.15.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.4.tgz", - "integrity": "sha512-6ln5i9Nkrb27X4w91ZPt/xHDsVQnvxTS2ntgq6r32u+8gymdUrp88TdcBXSveZW0Dl+M5v2H6K75kJhMvUGhjg==", + "version": "29.16.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.16.1.tgz", + "integrity": "sha512-tfxOIsjzaBud+f74aLbBMRcnrztt5eCIgnAdeoGdnzMAQ4IdAa/s/p8Ls55mk9MC79N3j2jbv4Qetz6Hclbcfw==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^8.0.0" @@ -8365,7 +8364,7 @@ "@typescript-eslint/eslint-plugin": "^8.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "jest": "*", - "typescript": ">=4.8.4 <7.0.0" + "typescript": ">=4.8.4 <8.0.0" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { @@ -8380,12 +8379,11 @@ } }, "node_modules/eslint-plugin-jest-dom": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.5.0.tgz", - "integrity": "sha512-CRlXfchTr7EgC3tDI7MGHY6QjdJU5Vv2RPaeeGtkXUHnKZf04kgzMPIJUXt4qKCvYWVVIEo9ut9Oq1vgXAykEA==", + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.10.1.tgz", + "integrity": "sha512-IIJdzbACbhJUJyMAqpA9E9gxp1Gv29TeQ3DtL+pepwP8Oq2WiqjOB2HbnEIs23h0ewdKIZRDI56yLro2eUO+DA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.16.3", "requireindex": "^1.2.0" }, "engines": { @@ -8395,7 +8393,7 @@ }, "peerDependencies": { "@testing-library/dom": "^8.0.0 || ^9.0.0 || ^10.0.0", - "eslint": "^6.8.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + "eslint": "^6.8.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" }, "peerDependenciesMeta": { "@testing-library/dom": { @@ -9347,9 +9345,9 @@ "dev": true }, "node_modules/globals": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz", - "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==", + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.11.0.tgz", + "integrity": "sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==", "dev": true, "engines": { "node": ">=18" @@ -9679,9 +9677,9 @@ } }, "node_modules/html-webpack-plugin": { - "version": "5.6.7", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.7.tgz", - "integrity": "sha512-md+vXtdCAe60s1k6AU3dUyMJnDxUyQAwfwPKoLisvgUF1IXjtlLsk2se54+qfL9Mdm26bbwvjJybpNx48NKRLw==", + "version": "5.6.8", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.8.tgz", + "integrity": "sha512-MZmKQcTnhEh1SPSyMiEytIeDZDUoBZVorNHivQGXMASHf/BSGGOrKa2xQ5bGx3TCe1n109ecCt+cpww7wwWhKA==", "dev": true, "dependencies": { "@types/html-minifier-terser": "^6.0.0", @@ -9698,7 +9696,7 @@ "url": "https://opencollective.com/html-webpack-plugin" }, "peerDependencies": { - "@rspack/core": "0.x || 1.x", + "@rspack/core": "0.x || 1.x || 2.x", "webpack": "^5.20.0" }, "peerDependenciesMeta": { @@ -11980,14 +11978,15 @@ "license": "MIT" }, "node_modules/json-e": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/json-e/-/json-e-4.8.2.tgz", - "integrity": "sha512-0EzcoDOkNdiAG66q9d1FGHaWJbFy6Sz2Tf9U4kXyV+nMEbA3NUnpiQBdJm3qTqa9js7fATq35/fRYT+RHZcvNw==", + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/json-e/-/json-e-4.8.4.tgz", + "integrity": "sha512-ilxMMkTN7Iv3zICTia7+c899JPbjQddvdyV9nkh/frdDESDhlt92czMTucKbuUoybLQJt9MUmJFqwfhOylzFEQ==", "dependencies": { - "json-stable-stringify-without-jsonify": "^1.0.1" + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash": "^4.17.23" }, "engines": { - "node": ">=12" + "node": ">=20" } }, "node_modules/json-parse-even-better-errors": { @@ -12095,19 +12094,6 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, - "node_modules/loader-runner": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", - "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", - "dev": true, - "engines": { - "node": ">=6.11.5" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -12121,10 +12107,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" }, "node_modules/lodash.debounce": { "version": "4.0.8", @@ -13530,9 +13515,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz", + "integrity": "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==", "dev": true, "license": "MIT", "dependencies": { @@ -13826,9 +13811,9 @@ } }, "node_modules/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", - "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "engines": { "node": ">=0.10.0" } @@ -13858,14 +13843,14 @@ "license": "MIT" }, "node_modules/react-dom": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", - "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.7" + "react": "^19.2.8" } }, "node_modules/react-is": { @@ -13921,19 +13906,18 @@ } }, "node_modules/react-router": { - "version": "7.18.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.1.tgz", - "integrity": "sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-8.3.0.tgz", + "integrity": "sha512-qyPMvW83jGIct3yiieisxdk9M745anqhpIMKN5m1t6yBMfgVPpt77aHOqs5fUlEJRMCGffg9BaQLH9oPVOL7xQ==", "dependencies": { - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0" + "cookie-es": "^3.1.1" }, "engines": { - "node": ">=20.0.0" + "node": ">=22.22.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" + "react": ">=19.2.7", + "react-dom": ">=19.2.7" }, "peerDependenciesMeta": { "react-dom": { @@ -13941,15 +13925,6 @@ } } }, - "node_modules/react-router/node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -13967,9 +13942,9 @@ } }, "node_modules/react-virtuoso": { - "version": "4.18.10", - "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.18.10.tgz", - "integrity": "sha512-P6GIZ7kWAPOYB2H16yRQNgy+VF9pJOuTFw1EUc1EAtCj5WxVSAF1Sql3x3fbLwaLeBFsiPnu+3U9o6sIOyTdFw==", + "version": "4.18.12", + "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.18.12.tgz", + "integrity": "sha512-6c1SnRicSBfG+WnbhcyJUxzDHvvxD3vsux/EpcfVbgB7clyP1Od2r81TAGTgwbL7U2qP889RR4u+CH6WjgpW0g==", "peerDependencies": { "react": ">=16 || >=17 || >= 18 || >= 19", "react-dom": ">=16 || >=17 || >= 18 || >=19" @@ -14531,9 +14506,9 @@ } }, "node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -14687,12 +14662,6 @@ "node": ">= 18" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", - "license": "MIT" - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -15649,9 +15618,9 @@ } }, "node_modules/ts-jest": { - "version": "29.4.11", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.11.tgz", - "integrity": "sha512-IrFl7l9AuB/qrNw5quqvAv/hmKMb8dhWOH4jQOGo0Oq8tCeo1O86/iTFG1FaRimgUkF13l4PcepO8ATFT6Ns4g==", + "version": "29.4.12", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.12.tgz", + "integrity": "sha512-Ov6ClY53Fflh6BGAnY2DlTq1hYDrTycz2PVTXBWFW2CU+9zrEqAp9fWdGXl42EXO5RLSFAcAZ2JFKbP+zBTFfw==", "dev": true, "dependencies": { "bs-logger": "^0.2.6", @@ -15660,7 +15629,7 @@ "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", - "semver": "^7.8.0", + "semver": "^7.8.5", "type-fest": "^4.41.0", "yargs-parser": "^21.1.1" }, @@ -16035,15 +16004,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.1.tgz", - "integrity": "sha512-vymnnM5g0AKQDSAyfP12nMIBvgwgA42syg74kkuZ4x1VuTzwQKwc5h9rGxeShCjny5o+zWAb6OEoz7XLgrIkIw==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.67.0.tgz", + "integrity": "sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "8.62.1", - "@typescript-eslint/parser": "8.62.1", - "@typescript-eslint/typescript-estree": "8.62.1", - "@typescript-eslint/utils": "8.62.1" + "@typescript-eslint/eslint-plugin": "8.67.0", + "@typescript-eslint/parser": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/utils": "8.67.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -16386,9 +16355,9 @@ } }, "node_modules/webpack": { - "version": "5.108.4", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.108.4.tgz", - "integrity": "sha512-yur8LyJoeiWh47dErD+Ok7vlbmDsJ3UbbRPAoxbGJ54WpE2y5yVo5G/inUzujnYgw3tPmBRdn+G7PoxXaYC33w==", + "version": "5.109.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.109.2.tgz", + "integrity": "sha512-U9/cvLzxObKNEZ9+TtdqrHM5/9z3lgl2c+c4BzbqGxFQvQvBAq87yql5A8pQ+rrMbS496MZJeF5enVBndIy2hw==", "dev": true, "dependencies": { "@types/estree": "^1.0.8", @@ -16397,22 +16366,20 @@ "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.16.0", - "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.22.2", + "enhanced-resolve": "^5.24.4", "es-module-lexer": "^2.1.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "graceful-fs": "^4.2.11", - "loader-runner": "^4.3.2", "mime-db": "^1.54.0", "minimizer-webpack-plugin": "^5.6.1", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", "watchpack": "^2.5.2", - "webpack-sources": "^3.5.0" + "webpack-sources": "^3.5.1" }, "bin": { "webpack": "bin/webpack.js" @@ -16833,9 +16800,9 @@ } }, "node_modules/webpack-sources": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", - "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.1.tgz", + "integrity": "sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw==", "dev": true, "engines": { "node": ">=10.13.0" @@ -19893,108 +19860,108 @@ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==" }, "@swc/core": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.43.tgz", - "integrity": "sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw==", - "dev": true, - "requires": { - "@swc/core-darwin-arm64": "1.15.43", - "@swc/core-darwin-x64": "1.15.43", - "@swc/core-linux-arm-gnueabihf": "1.15.43", - "@swc/core-linux-arm64-gnu": "1.15.43", - "@swc/core-linux-arm64-musl": "1.15.43", - "@swc/core-linux-ppc64-gnu": "1.15.43", - "@swc/core-linux-s390x-gnu": "1.15.43", - "@swc/core-linux-x64-gnu": "1.15.43", - "@swc/core-linux-x64-musl": "1.15.43", - "@swc/core-win32-arm64-msvc": "1.15.43", - "@swc/core-win32-ia32-msvc": "1.15.43", - "@swc/core-win32-x64-msvc": "1.15.43", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.16.1.tgz", + "integrity": "sha512-nUaeu91O5QZKrQdaDCHd402ogUIoNOOjpkZNq0UomWK0G6gDaGmLhvddF1/3BXf5O8aLyo6ZPY/aMDWvaJQ/hg==", + "dev": true, + "requires": { + "@swc/core-darwin-arm64": "1.16.1", + "@swc/core-darwin-x64": "1.16.1", + "@swc/core-linux-arm-gnueabihf": "1.16.1", + "@swc/core-linux-arm64-gnu": "1.16.1", + "@swc/core-linux-arm64-musl": "1.16.1", + "@swc/core-linux-ppc64-gnu": "1.16.1", + "@swc/core-linux-s390x-gnu": "1.16.1", + "@swc/core-linux-x64-gnu": "1.16.1", + "@swc/core-linux-x64-musl": "1.16.1", + "@swc/core-win32-arm64-msvc": "1.16.1", + "@swc/core-win32-ia32-msvc": "1.16.1", + "@swc/core-win32-x64-msvc": "1.16.1", "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.27" + "@swc/types": "^0.1.28" } }, "@swc/core-darwin-arm64": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.43.tgz", - "integrity": "sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.16.1.tgz", + "integrity": "sha512-zlJblJ8ncErD43lKdxjbUaUskJQf+LxiPXYcWXD8/8ZMV+7uuAT+CwjciLXpyZBd5Pq/S726bMpeeAwSeL1hhg==", "dev": true, "optional": true }, "@swc/core-darwin-x64": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.43.tgz", - "integrity": "sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.16.1.tgz", + "integrity": "sha512-IN0BmPWb0YAh/17mmlWB/HDBtTw2MfuW4hulf/tQAgTQBRH17l+z499bNJLK6LizSjqs0P7V+jU38Zj+vJC1DA==", "dev": true, "optional": true }, "@swc/core-linux-arm-gnueabihf": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.43.tgz", - "integrity": "sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.16.1.tgz", + "integrity": "sha512-EYgrx2YOCQ2Twz2S793kqNjPkpvYVUPzzR95bIb7by+VQcyaai4lZZ2iz/tZvcFVKSNcN3/JTKwx+aBn2ZL52A==", "dev": true, "optional": true }, "@swc/core-linux-arm64-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.43.tgz", - "integrity": "sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.16.1.tgz", + "integrity": "sha512-moyKm0YZlHdHohzm1YwgAyesqnE853rO0REMfJLFAova51wF9BNi+3ZW2PeS7Vqvn6HeJuepLpAHbBdZctxpHA==", "dev": true, "optional": true }, "@swc/core-linux-arm64-musl": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.43.tgz", - "integrity": "sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.16.1.tgz", + "integrity": "sha512-kKGBO9wdapiSzuf5ZzZ2fYtlu1BNSYtIIUxvH1ir/gcelTOREEHGDCLTDFx/2Knf878nU11A40z7LxwasEFxqA==", "dev": true, "optional": true }, "@swc/core-linux-ppc64-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.43.tgz", - "integrity": "sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.16.1.tgz", + "integrity": "sha512-nZ6qahtLxC3PM54cWOQZHxt4lTCF/3J4LIoWWzz6v7A+rLs8Dx54anYQf7mH3eIi8KlNpgKci/ie8ZSqFN8O7A==", "dev": true, "optional": true }, "@swc/core-linux-s390x-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.43.tgz", - "integrity": "sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.16.1.tgz", + "integrity": "sha512-4ji5PNzhYq193Z4/4xUaSoNJza6iCkDJSzhetrbB6KOYxsr+kxtQr8ePWhMJUiMt6JUWtXaZ1PYT8FhtED+nGA==", "dev": true, "optional": true }, "@swc/core-linux-x64-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.43.tgz", - "integrity": "sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.16.1.tgz", + "integrity": "sha512-VJQxqrisHV+B394IgrOu8YsIIXZgffnf5tO+yc9Z/hoUpuZEvuQTjWwlnpZdpyD+0nx6LTD1/3k646JYm43yJA==", "dev": true, "optional": true }, "@swc/core-linux-x64-musl": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.43.tgz", - "integrity": "sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.16.1.tgz", + "integrity": "sha512-r9oV1mwxxsIGcLV1IQ/tw76MW3doatKze1QFWuC+a7QqJUkhY/bKTSVk6NpKKUGm2LDsE33Va8VqSClfA7vSiQ==", "dev": true, "optional": true }, "@swc/core-win32-arm64-msvc": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.43.tgz", - "integrity": "sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.16.1.tgz", + "integrity": "sha512-6huNRessoBLxWEqBm5zJXyCQ27TO7anvkdiuQ5MDO4CJni0nOXEqKtV9RllQ2TdyENKKsUMXVnIfW2hIXx/R5Q==", "dev": true, "optional": true }, "@swc/core-win32-ia32-msvc": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.43.tgz", - "integrity": "sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.16.1.tgz", + "integrity": "sha512-OVKJFUzphrGmsh+BGtcZDesx0YryV7/Yvy5XGgTqnrZfjnyfcr5uaqYQugCckdIlupc5Vs3XtDjRAj12z4ZPlw==", "dev": true, "optional": true }, "@swc/core-win32-x64-msvc": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.43.tgz", - "integrity": "sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.16.1.tgz", + "integrity": "sha512-Bt+VIhWYCGk4urklnkkteLUOeLv1VxigwTCeB/xC6rBZxY6IIKdDwCJf6on3E3SUGsIqmQS6QqtuJQc1VxF4Aw==", "dev": true, "optional": true }, @@ -20016,9 +19983,9 @@ } }, "@swc/types": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.27.tgz", - "integrity": "sha512-K6h3iUlqeM946U4sXFYeahefR1YBbXJvko+hv8WS8/0BNJ4OHiHRywMnQUJCqkR7Y9+hqQ1TvEpiKqUhz7NEFg==", + "version": "0.1.28", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.28.tgz", + "integrity": "sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw==", "dev": true, "requires": { "@swc/counter": "^0.1.3" @@ -20068,9 +20035,9 @@ } }, "@testing-library/jest-dom": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", - "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.10.0.tgz", + "integrity": "sha512-HQwu0KaB2zyT0iLzBL+8CLyZDL3KlZlZJ+2iyc9uCUnlJVskJU/UlPuVCyIPhtukjPQdT2QNoR5nCP5FqTmmDQ==", "dev": true, "requires": { "@adobe/css-tools": "^4.4.0", @@ -20099,9 +20066,9 @@ } }, "@testing-library/user-event": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", - "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "version": "14.6.6", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.6.tgz", + "integrity": "sha512-Jbs9FpkkIDw8FgSc6kOVsOv8JuuqGAL7J4X1oot77JxAoDlkNn2GRkd0aYRVuQ+pVQAiHWVkE4rX/dkF5fBiCw==", "dev": true, "requires": {} }, @@ -20442,9 +20409,9 @@ "dev": true }, "@types/react": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", - "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", "requires": { "csstype": "^3.2.2" } @@ -20459,9 +20426,9 @@ } }, "@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-fMPwH9v7r/pp43yUd2/Mbiex5KouJwwR3dzHkhLREUC6764VyDsqxhAxv6OFEYR1RhjOyD1naqba8ECDBe7ZQg==", "dev": true, "requires": {} }, @@ -20558,16 +20525,16 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.1.tgz", - "integrity": "sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.67.0.tgz", + "integrity": "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.62.1", - "@typescript-eslint/type-utils": "8.62.1", - "@typescript-eslint/utils": "8.62.1", - "@typescript-eslint/visitor-keys": "8.62.1", + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/type-utils": "8.67.0", + "@typescript-eslint/utils": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -20582,75 +20549,75 @@ } }, "@typescript-eslint/parser": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.1.tgz", - "integrity": "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.67.0.tgz", + "integrity": "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "8.62.1", - "@typescript-eslint/types": "8.62.1", - "@typescript-eslint/typescript-estree": "8.62.1", - "@typescript-eslint/visitor-keys": "8.62.1", + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", "debug": "^4.4.3" } }, "@typescript-eslint/project-service": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.1.tgz", - "integrity": "sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.67.0.tgz", + "integrity": "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==", "dev": true, "requires": { - "@typescript-eslint/tsconfig-utils": "^8.62.1", - "@typescript-eslint/types": "^8.62.1", + "@typescript-eslint/tsconfig-utils": "^8.67.0", + "@typescript-eslint/types": "^8.67.0", "debug": "^4.4.3" } }, "@typescript-eslint/scope-manager": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.1.tgz", - "integrity": "sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz", + "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==", "dev": true, "requires": { - "@typescript-eslint/types": "8.62.1", - "@typescript-eslint/visitor-keys": "8.62.1" + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0" } }, "@typescript-eslint/tsconfig-utils": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.1.tgz", - "integrity": "sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.67.0.tgz", + "integrity": "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==", "dev": true, "requires": {} }, "@typescript-eslint/type-utils": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.1.tgz", - "integrity": "sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.67.0.tgz", + "integrity": "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==", "dev": true, "requires": { - "@typescript-eslint/types": "8.62.1", - "@typescript-eslint/typescript-estree": "8.62.1", - "@typescript-eslint/utils": "8.62.1", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/utils": "8.67.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" } }, "@typescript-eslint/types": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.1.tgz", - "integrity": "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", + "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.1.tgz", - "integrity": "sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz", + "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==", "dev": true, "requires": { - "@typescript-eslint/project-service": "8.62.1", - "@typescript-eslint/tsconfig-utils": "8.62.1", - "@typescript-eslint/types": "8.62.1", - "@typescript-eslint/visitor-keys": "8.62.1", + "@typescript-eslint/project-service": "8.67.0", + "@typescript-eslint/tsconfig-utils": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -20665,44 +20632,44 @@ "dev": true }, "brace-expansion": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", - "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "requires": { "balanced-match": "^4.0.2" } }, "minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, "requires": { - "brace-expansion": "^5.0.5" + "brace-expansion": "^5.0.8" } } } }, "@typescript-eslint/utils": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.1.tgz", - "integrity": "sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz", + "integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.62.1", - "@typescript-eslint/types": "8.62.1", - "@typescript-eslint/typescript-estree": "8.62.1" + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0" } }, "@typescript-eslint/visitor-keys": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.1.tgz", - "integrity": "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz", + "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==", "dev": true, "requires": { - "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/types": "8.67.0", "eslint-visitor-keys": "^5.0.0" }, "dependencies": { @@ -21051,13 +21018,6 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true }, - "acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", - "dev": true, - "requires": {} - }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -22098,6 +22058,11 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==" }, + "cookie-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz", + "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==" + }, "cookie-signature": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", @@ -22117,9 +22082,9 @@ } }, "core-js": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", - "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.50.0.tgz", + "integrity": "sha512-BRWgOLKkFeCgRudR6zrs8p9XJZcE14grzKMMssoYrk6krtuEZ7MTKPIY5RzOnqsEKIR9kst7wNzphttraT+Yqw==", "dev": true }, "core-js-compat": { @@ -22341,9 +22306,9 @@ } }, "dayjs": { - "version": "1.11.21", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", - "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==" + "version": "1.11.23", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.23.tgz", + "integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==" }, "debug": { "version": "4.4.3", @@ -22654,9 +22619,9 @@ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" }, "enhanced-resolve": { - "version": "5.23.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.23.0.tgz", - "integrity": "sha512-yJN/BOOLxcOW2aQgeif9mSnaUB8KtvmMMp56oA1kx1CRfBKbhZm2pJ+NBY+3eOboHxix8lfjWpHE0Ei5U8RbSA==", + "version": "5.24.5", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", + "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -23057,21 +23022,20 @@ } }, "eslint-plugin-jest": { - "version": "29.15.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.4.tgz", - "integrity": "sha512-6ln5i9Nkrb27X4w91ZPt/xHDsVQnvxTS2ntgq6r32u+8gymdUrp88TdcBXSveZW0Dl+M5v2H6K75kJhMvUGhjg==", + "version": "29.16.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.16.1.tgz", + "integrity": "sha512-tfxOIsjzaBud+f74aLbBMRcnrztt5eCIgnAdeoGdnzMAQ4IdAa/s/p8Ls55mk9MC79N3j2jbv4Qetz6Hclbcfw==", "dev": true, "requires": { "@typescript-eslint/utils": "^8.0.0" } }, "eslint-plugin-jest-dom": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.5.0.tgz", - "integrity": "sha512-CRlXfchTr7EgC3tDI7MGHY6QjdJU5Vv2RPaeeGtkXUHnKZf04kgzMPIJUXt4qKCvYWVVIEo9ut9Oq1vgXAykEA==", + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.10.1.tgz", + "integrity": "sha512-IIJdzbACbhJUJyMAqpA9E9gxp1Gv29TeQ3DtL+pepwP8Oq2WiqjOB2HbnEIs23h0ewdKIZRDI56yLro2eUO+DA==", "dev": true, "requires": { - "@babel/runtime": "^7.16.3", "requireindex": "^1.2.0" } }, @@ -23680,9 +23644,9 @@ "dev": true }, "globals": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz", - "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==", + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.11.0.tgz", + "integrity": "sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==", "dev": true }, "globalthis": { @@ -23937,9 +23901,9 @@ } }, "html-webpack-plugin": { - "version": "5.6.7", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.7.tgz", - "integrity": "sha512-md+vXtdCAe60s1k6AU3dUyMJnDxUyQAwfwPKoLisvgUF1IXjtlLsk2se54+qfL9Mdm26bbwvjJybpNx48NKRLw==", + "version": "5.6.8", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.8.tgz", + "integrity": "sha512-MZmKQcTnhEh1SPSyMiEytIeDZDUoBZVorNHivQGXMASHf/BSGGOrKa2xQ5bGx3TCe1n109ecCt+cpww7wwWhKA==", "dev": true, "requires": { "@types/html-minifier-terser": "^6.0.0", @@ -25527,11 +25491,12 @@ "dev": true }, "json-e": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/json-e/-/json-e-4.8.2.tgz", - "integrity": "sha512-0EzcoDOkNdiAG66q9d1FGHaWJbFy6Sz2Tf9U4kXyV+nMEbA3NUnpiQBdJm3qTqa9js7fATq35/fRYT+RHZcvNw==", + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/json-e/-/json-e-4.8.4.tgz", + "integrity": "sha512-ilxMMkTN7Iv3zICTia7+c899JPbjQddvdyV9nkh/frdDESDhlt92czMTucKbuUoybLQJt9MUmJFqwfhOylzFEQ==", "requires": { - "json-stable-stringify-without-jsonify": "^1.0.1" + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash": "^4.17.23" } }, "json-parse-even-better-errors": { @@ -25618,12 +25583,6 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, - "loader-runner": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", - "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", - "dev": true - }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -25634,10 +25593,9 @@ } }, "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" }, "lodash.debounce": { "version": "4.0.8", @@ -26570,9 +26528,9 @@ } }, "postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz", + "integrity": "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -26797,9 +26755,9 @@ } }, "react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", - "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==" + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==" }, "react-app-polyfill": { "version": "3.0.0", @@ -26824,9 +26782,9 @@ } }, "react-dom": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", - "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "requires": { "scheduler": "^0.27.0" } @@ -26865,19 +26823,11 @@ "dev": true }, "react-router": { - "version": "7.18.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.1.tgz", - "integrity": "sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-8.3.0.tgz", + "integrity": "sha512-qyPMvW83jGIct3yiieisxdk9M745anqhpIMKN5m1t6yBMfgVPpt77aHOqs5fUlEJRMCGffg9BaQLH9oPVOL7xQ==", "requires": { - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0" - }, - "dependencies": { - "cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==" - } + "cookie-es": "^3.1.1" } }, "react-transition-group": { @@ -26892,9 +26842,9 @@ } }, "react-virtuoso": { - "version": "4.18.10", - "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.18.10.tgz", - "integrity": "sha512-P6GIZ7kWAPOYB2H16yRQNgy+VF9pJOuTFw1EUc1EAtCj5WxVSAF1Sql3x3fbLwaLeBFsiPnu+3U9o6sIOyTdFw==", + "version": "4.18.12", + "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.18.12.tgz", + "integrity": "sha512-6c1SnRicSBfG+WnbhcyJUxzDHvvxD3vsux/EpcfVbgB7clyP1Od2r81TAGTgwbL7U2qP889RR4u+CH6WjgpW0g==", "requires": {} }, "read-package-json-fast": { @@ -27313,9 +27263,9 @@ } }, "semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true }, "send": { @@ -27439,11 +27389,6 @@ "send": "^1.2.0" } }, - "set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==" - }, "set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -28111,9 +28056,9 @@ "requires": {} }, "ts-jest": { - "version": "29.4.11", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.11.tgz", - "integrity": "sha512-IrFl7l9AuB/qrNw5quqvAv/hmKMb8dhWOH4jQOGo0Oq8tCeo1O86/iTFG1FaRimgUkF13l4PcepO8ATFT6Ns4g==", + "version": "29.4.12", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.12.tgz", + "integrity": "sha512-Ov6ClY53Fflh6BGAnY2DlTq1hYDrTycz2PVTXBWFW2CU+9zrEqAp9fWdGXl42EXO5RLSFAcAZ2JFKbP+zBTFfw==", "dev": true, "requires": { "bs-logger": "^0.2.6", @@ -28122,7 +28067,7 @@ "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", - "semver": "^7.8.0", + "semver": "^7.8.5", "type-fest": "^4.41.0", "yargs-parser": "^21.1.1" }, @@ -28352,15 +28297,15 @@ "dev": true }, "typescript-eslint": { - "version": "8.62.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.1.tgz", - "integrity": "sha512-vymnnM5g0AKQDSAyfP12nMIBvgwgA42syg74kkuZ4x1VuTzwQKwc5h9rGxeShCjny5o+zWAb6OEoz7XLgrIkIw==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.67.0.tgz", + "integrity": "sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==", "dev": true, "requires": { - "@typescript-eslint/eslint-plugin": "8.62.1", - "@typescript-eslint/parser": "8.62.1", - "@typescript-eslint/typescript-estree": "8.62.1", - "@typescript-eslint/utils": "8.62.1" + "@typescript-eslint/eslint-plugin": "8.67.0", + "@typescript-eslint/parser": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/utils": "8.67.0" } }, "typestyle": { @@ -28614,9 +28559,9 @@ "dev": true }, "webpack": { - "version": "5.108.4", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.108.4.tgz", - "integrity": "sha512-yur8LyJoeiWh47dErD+Ok7vlbmDsJ3UbbRPAoxbGJ54WpE2y5yVo5G/inUzujnYgw3tPmBRdn+G7PoxXaYC33w==", + "version": "5.109.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.109.2.tgz", + "integrity": "sha512-U9/cvLzxObKNEZ9+TtdqrHM5/9z3lgl2c+c4BzbqGxFQvQvBAq87yql5A8pQ+rrMbS496MZJeF5enVBndIy2hw==", "dev": true, "requires": { "@types/estree": "^1.0.8", @@ -28625,22 +28570,20 @@ "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.16.0", - "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.22.2", + "enhanced-resolve": "^5.24.4", "es-module-lexer": "^2.1.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "graceful-fs": "^4.2.11", - "loader-runner": "^4.3.2", "mime-db": "^1.54.0", "minimizer-webpack-plugin": "^5.6.1", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", "watchpack": "^2.5.2", - "webpack-sources": "^3.5.0" + "webpack-sources": "^3.5.1" }, "dependencies": { "mime-db": { @@ -28938,9 +28881,9 @@ } }, "webpack-sources": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", - "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.1.tgz", + "integrity": "sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw==", "dev": true }, "websocket-driver": { diff --git a/package.json b/package.json index cb29b4e3f..1fcc6e642 100644 --- a/package.json +++ b/package.json @@ -23,21 +23,21 @@ "assert": "^2.1.0", "buffer": "^6.0.3", "crypto-browserify": "^3.12.1", - "dayjs": "^1.11.21", + "dayjs": "^1.11.23", "echarts": "^6.1.0", "express": "^5.2.1", "fast-kde": "^0.2.2", "format": "^0.2.2", - "json-e": "^4.8.2", + "json-e": "^4.8.4", "material-ui-popup-state": "^5.3.7", "moize": "^6.1.7", "notistack": "^3.0.2", "process": "^0.11.10", - "react": "^19.2.7", - "react-dom": "^19.2.7", + "react": "^19.2.8", + "react-dom": "^19.2.8", "react-redux": "^9.3.0", - "react-router": "^7.18.1", - "react-virtuoso": "^4.18.10", + "react-router": "^8.3.0", + "react-virtuoso": "^4.18.12", "stream-browserify": "^3.0.0", "taskcluster-client-web": "^87.1.3", "taskcluster-lib-scopes": "^11.0.0", @@ -89,35 +89,35 @@ "@eslint/js": "^9.39.5", "@fetch-mock/jest": "^0.2.20", "@jest/types": "^30.4.1", - "@swc/core": "^1.15.43", + "@swc/core": "^1.16.1", "@swc/jest": "^0.2.39", "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^6.9.1", + "@testing-library/jest-dom": "^6.10.0", "@testing-library/react": "^16.3.2", - "@testing-library/user-event": "^14.6.1", + "@testing-library/user-event": "^14.6.6", "@types/jest": "^30.0.0", "@types/jest-axe": "^3.5.9", "@types/material-ui": "^0.21.18", "@types/node": "^25.9.5", - "@types/react": "^19.2.17", - "@types/react-dom": "^19.2.3", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.5", "babel-loader": "^10.1.1", "babel-preset-jest": "^30.4.0", "case-sensitive-paths-webpack-plugin": "^2.4.0", "copy-webpack-plugin": "^13.0.1", - "core-js": "^3.49.0", + "core-js": "^3.50.0", "css-loader": "^7.1.4", "eslint": "^9.39.5", "eslint-config-prettier": "^10.1.8", "eslint-import-resolver-typescript": "^4.4.5", "eslint-plugin-import": "^2.32.0", - "eslint-plugin-jest": "^29.15.4", - "eslint-plugin-jest-dom": "^5.5.0", + "eslint-plugin-jest": "^29.16.1", + "eslint-plugin-jest-dom": "^5.10.1", "eslint-plugin-react": "^7.37.5", "eslint-plugin-testing-library": "^7.16.2", - "globals": "^17.7.0", + "globals": "^17.11.0", "history": "^5.3.0", - "html-webpack-plugin": "^5.6.7", + "html-webpack-plugin": "^5.6.8", "jest": "^30.4.2", "jest-axe": "^10.0.0", "jest-environment-jsdom": "^30.4.1", @@ -128,12 +128,12 @@ "react-refresh": "^0.18.0", "regenerator-runtime": "^0.14.1", "style-loader": "^4.0.0", - "ts-jest": "^29.4.11", + "ts-jest": "^29.4.12", "ts-loader": "^9.6.2", "ts-node": "^10.9.2", "typescript": "^5.9.3", - "typescript-eslint": "^8.62.1", - "webpack": "^5.108.4", + "typescript-eslint": "^8.67.0", + "webpack": "^5.109.2", "webpack-cli": "^6.0.1", "webpack-dev-server": "^5.2.6", "webpack-merge": "^6.0.1" diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx index a418178d9..378d344db 100644 --- a/src/__tests__/App.test.tsx +++ b/src/__tests__/App.test.tsx @@ -3,7 +3,7 @@ import userEvent from '@testing-library/user-event'; import App, { router } from '../components/App'; import getTestData from './utils/fixtures'; -import { act, render, screen } from './utils/test-utils'; +import { act, render, screen, within } from './utils/test-utils'; describe('App', () => { beforeEach(() => { @@ -96,10 +96,12 @@ describe('App', () => { }); await user.click(darkModeButton); - expect(screen.getByLabelText('Light mode')).toBeInTheDocument(); + expect(screen.getByLabelText('Switch to Light mode')).toBeInTheDocument(); await user.click(darkModeButton); - expect(screen.queryByLabelText('Light mode')).not.toBeInTheDocument(); + expect( + screen.queryByLabelText('Switch to Light mode'), + ).not.toBeInTheDocument(); }); describe('CompareResults or CompareOverTime loader', () => { @@ -396,11 +398,13 @@ describe('App', () => { // Wait for the page to load await screen.findByText('a11yr'); - // Verify that Mann-Whitney-U specific columns are rendered - // (this indicates the testVersion defaulted to mann-whitney-u) - expect(screen.getByText('CD')).toBeInTheDocument(); - expect(screen.getByText('Sig')).toBeInTheDocument(); - expect(screen.getByText('CLES (%)')).toBeInTheDocument(); + // Verify a Mann-Whitney-U specific column is rendered — "Δ Median" is + // unique to the Mann-Whitney strategy (Student-T uses "Delta"), so its + // presence in the table header indicates the testVersion defaulted to + // mann-whitney-u. Scope to the header since the "How to read the results" + // panel also names it. + const tableHeader = screen.getByTestId('table-header'); + expect(within(tableHeader).getByText('Δ Median')).toBeInTheDocument(); // Verify the Stats Test Version dropdown shows Mann-Whitney-U as selected const testVersionDropdown = screen.getByRole('combobox', { diff --git a/src/__tests__/CompareResults/ResultsTable.test.tsx b/src/__tests__/CompareResults/ResultsTable.test.tsx index c663ada1d..5562eb684 100644 --- a/src/__tests__/CompareResults/ResultsTable.test.tsx +++ b/src/__tests__/CompareResults/ResultsTable.test.tsx @@ -14,7 +14,13 @@ import getTestData, { augmentCompareMannWhitneyDataWithSeveralRevisions, augmentCompareMannWhitneyDataWithSeveralTests, } from '../utils/fixtures'; -import { renderWithRouter, screen, waitFor, within } from '../utils/test-utils'; +import { + renderWithRouter, + screen, + waitFor, + within, + enableAdvancedColumns, +} from '../utils/test-utils'; function renderWithRoute(component: ReactElement, extraParameters?: string) { return renderWithRouter(component, { @@ -48,7 +54,7 @@ function setupAndRender( // This handy function parses the results page and returns an array of visible // rows. It makes it easy to assert visible rows when filtering them in a // user-friendly way without using snapshots. -function summarizeVisibleRows(testVersion?: TestVersion) { +function summarizeVisibleRows(testVersion?: TestVersion, advanced = false) { const rowGroups = screen.getAllByRole('rowgroup'); const result = []; @@ -83,17 +89,34 @@ function summarizeVisibleRows(testVersion?: TestVersion) { for (const row of rows) { const rowClasses = testVersion === 'mann-whitney-u' - ? [ - '.platform span', - '.median-diff', - '.status', - '.delta', - '.significance', - '.effects', - ] + ? advanced + ? [ + '.platform span', + '.median-diff', + '.status-hint', + '.delta', + '.significance', + '.effects', + ] + : [ + '.platform span', + '.median-diff', + '.status-hint', + '.magnitude', + '.significance', + ] : ['.platform span', '.status', '.delta', '.confidence']; const rowString = rowClasses - .map((selector) => row.querySelector(selector)?.textContent?.trim()) + .map((selector) => { + const cell = row.querySelector(selector); + if (!cell) return undefined; + // Strip icon text (e.g. the median-diff normality warning) + // so the data-focused expectations stay stable; icon presence is + // asserted separately. + const clone = cell.cloneNode(true) as HTMLElement; + clone.querySelectorAll('svg').forEach((svg) => svg.remove()); + return clone.textContent?.trim(); + }) .join(', '); result.push(' - ' + rowString); @@ -690,6 +713,13 @@ describe('Results Table', () => { }); describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion', () => { + // These tests exercise the full (advanced) table — CD, CLES, Sig columns and + // their sort/filter behavior. The simplified default view (which hides + // CD/CLES and shows the Magnitude column) is covered separately below. + beforeEach(() => { + enableAdvancedColumns(); + }); + it('Should match snapshot', async () => { const { testCompareMannWhitneyData } = getTestData(); @@ -719,12 +749,12 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio setupAndRender(simplerTestCompareData, 'test_version=mann-whitney-u'); await screen.findByText('a11yr'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: spam', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', ' rev: devilrabbit', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', ]); expect(screen.getByRole('rowgroup')).toMatchSnapshot(); }); @@ -746,25 +776,25 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); await screen.findByText('a11yr'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - inexistant, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Android, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - inexistant, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({}); const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); await clickMenuItem(user, 'Platform', /Windows/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Android, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['osx', 'linux', 'android', 'ios'], @@ -773,78 +803,78 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio // Clicking Windows again should remove the search param and make the // "inexitant" platform visible again. await clickMenuItem(user, 'Platform', /Windows/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - inexistant, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Android, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - inexistant, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({}); await clickMenuItem(user, 'Platform', /Windows/); await clickMenuItem(user, 'Platform', /Linux/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Android, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['osx', 'android', 'ios'], }); await clickMenuItem(user, 'Platform', /Linux/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Android, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['osx', 'android', 'ios', 'linux'], }); await clickMenuItem(user, 'Platform', 'Select all values'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - inexistant, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Android, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - inexistant, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({}); await clickMenuItem(user, 'Platform', /macOS/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Android, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['windows', 'linux', 'android', 'ios'], }); await clickMenuItem(user, 'Platform', /Android/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['windows', 'linux', 'ios'], }); await clickMenuItem(user, 'Platform', /Select only.*Android/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Android, +1.08%, Improvement, 0.1, Noise, 25.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['android'], @@ -858,16 +888,16 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); - // Filter only "Significant" + // Filter only "Real" (significant) const signifianceMenu = await screen.findByRole('button', { name: /Sig.*filter/, }); await user.click(signifianceMenu); expect(signifianceMenu).toMatchSnapshot(); - // significant item 0 and Not significant item 1 + // "Real" is item 0, "Noise" (not significant) is item 1 const significantOptions = await screen.findAllByRole('menuitemcheckbox', { - name: /Significant/, + name: /Real|Noise/, }); await user.click(significantOptions[1]); await user.keyboard('[Escape]'); @@ -881,74 +911,49 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); await screen.findByText('a11yr'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({}); const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); - await clickMenuItem(user, 'Status', /No changes/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ]); - expect(summarizeTableFiltersFromUrl()).toEqual({ - status: ['improvement', 'regression'], - }); - await clickMenuItem(user, 'Status', /Improvement/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + // Noise is mutually exclusive with the direction buckets: selecting only + // Noise shows the not-significant rows regardless of their direction. + await clickMenuItem(user, 'Status', /Select only.*Noise/); + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', ]); - expect(summarizeTableFiltersFromUrl()).toEqual({ - status: ['regression'], - }); + expect(summarizeTableFiltersFromUrl()).toEqual({ status: ['noise'] }); + // Unchecking Noise (the three direction buckets stay checked) hides the + // noisy rows and leaves only the real (significant) rows. await clickMenuItem(user, 'Status', /Select all values/); - await clickMenuItem(user, 'Status', /Regression/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + await clickMenuItem(user, 'Status', /^Noise/); + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ - status: ['none', 'improvement'], + status: ['none', 'improvement', 'regression'], }); - await clickMenuItem(user, 'Status', /Regression/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', - ]); - expect(summarizeTableFiltersFromUrl()).toEqual({}); - - await clickMenuItem(user, 'Status', /Select only.*Regression/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + // A direction bucket only matches real rows, so "No changes" shows the two + // significant no-change rows. + await clickMenuItem(user, 'Status', /Select only.*No changes/); + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', ]); - expect(summarizeTableFiltersFromUrl()).toEqual({ - status: ['regression'], - }); - - await clickMenuItem(user, 'Status', /Select only.*Improvement/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ]); - expect(summarizeTableFiltersFromUrl()).toEqual({ - status: ['improvement'], - }); + expect(summarizeTableFiltersFromUrl()).toEqual({ status: ['none'] }); }); it('can load the filter parameters from the URL on mann-whitney-u test_version', async () => { @@ -959,15 +964,15 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio ); await screen.findByText('dhtml.html'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', ]); const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); expect(await summarizeTableFiltersFromCheckboxes(user)).toEqual({ 'Platform(2)': ['macOS', 'Android'], - 'Sig(2)': ['Significant', 'Not Significant-'], - 'Status(3)': ['No changes', 'Improvement', 'Regression'], + 'Sig(2)': ['Real', 'Noise'], + 'Status(4)': ['No changes', 'Improvement', 'Regression', 'Noise'], }); // After a change, "foo" should disappear @@ -994,29 +999,29 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio expect(deltaButton).toMatchSnapshot(); // // Sort descending - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr aria.html opt e10s fission stylo webrender', ' rev: spam', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', - ' - Windows 10, -, , 1.2, , 99.00 %', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, Noise, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, Noise, 24.00 %', + ' - Windows 10, -, , 1.2, Real, 99.00 %', + ' - Windows 10, -2.40%, , 1.2, Real, 49.00 %', ' rev: tictactoe', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', - ' - Windows 10, -, , 2, , 98.00 %', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, Noise, 43.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, Noise, 23.00 %', + ' - Windows 10, -, , 2, Real, 98.00 %', + ' - Windows 10, -2.40%, , 2, Real, 48.00 %', 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: spam', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', ' rev: tictactoe', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', - ' - Windows 10, -, , 0.8, , 99.00 %', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, Noise, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, Noise, 24.00 %', + ' - Windows 10, -, , 0.8, Real, 99.00 %', + ' - Windows 10, -2.40%, , 0.8, Real, 49.00 %', ]); // It should have the "descending" SVG. expect(deltaButton).toMatchSnapshot(); @@ -1025,29 +1030,29 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio // sort ascending await user.click(deltaButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr aria.html opt e10s fission stylo webrender', ' rev: tictactoe', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', - ' - Windows 10, -, , 2, , 98.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, Noise, 23.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, Noise, 43.00 %', + ' - Windows 10, -2.40%, , 2, Real, 48.00 %', + ' - Windows 10, -, , 2, Real, 98.00 %', ' rev: spam', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', - ' - Windows 10, -, , 1.2, , 99.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, Noise, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, Noise, 44.00 %', + ' - Windows 10, -2.40%, , 1.2, Real, 49.00 %', + ' - Windows 10, -, , 1.2, Real, 99.00 %', 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: tictactoe', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', - ' - Windows 10, -, , 0.8, , 99.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, Noise, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, Noise, 44.00 %', + ' - Windows 10, -2.40%, , 0.8, Real, 49.00 %', + ' - Windows 10, -, , 0.8, Real, 99.00 %', ' rev: spam', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', - ' - Windows 10, -, , -, , 100.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', ]); // It should have the "ascending" SVG. expect(deltaButton).toMatchSnapshot(); @@ -1059,29 +1064,29 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio name: /Sig.*sort/, }); await user.click(significanceButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr aria.html opt e10s fission stylo webrender', ' rev: tictactoe', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', - ' - Windows 10, -, , 2, , 98.00 %', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, Noise, 23.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, Noise, 43.00 %', + ' - Windows 10, -, , 2, Real, 98.00 %', + ' - Windows 10, -2.40%, , 2, Real, 48.00 %', ' rev: spam', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', - ' - Windows 10, -, , 1.2, , 99.00 %', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, Noise, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, Noise, 44.00 %', + ' - Windows 10, -, , 1.2, Real, 99.00 %', + ' - Windows 10, -2.40%, , 1.2, Real, 49.00 %', 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: tictactoe', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', - ' - Windows 10, -, , 0.8, , 99.00 %', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, Noise, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, Noise, 44.00 %', + ' - Windows 10, -, , 0.8, Real, 99.00 %', + ' - Windows 10, -2.40%, , 0.8, Real, 49.00 %', ' rev: spam', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', ]); // It should have the "descending" SVG. expect(significanceButton).toMatchSnapshot(); @@ -1090,29 +1095,29 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio // Sort by Significance ascending await user.click(significanceButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: spam', - ' - Windows 10, -2.401 %, , -, , 50.00 %', - ' - Windows 10, -, , -, , 100.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', ' rev: tictactoe', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', - ' - Windows 10, -, , 0.8, , 99.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', + ' - Windows 10, -2.40%, , 0.8, Real, 49.00 %', + ' - Windows 10, -, , 0.8, Real, 99.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, Noise, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, Noise, 44.00 %', 'a11yr aria.html opt e10s fission stylo webrender', ' rev: spam', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', - ' - Windows 10, -, , 1.2, , 99.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', + ' - Windows 10, -2.40%, , 1.2, Real, 49.00 %', + ' - Windows 10, -, , 1.2, Real, 99.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, Noise, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, Noise, 44.00 %', ' rev: tictactoe', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', - ' - Windows 10, -, , 2, , 98.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', + ' - Windows 10, -2.40%, , 2, Real, 48.00 %', + ' - Windows 10, -, , 2, Real, 98.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, Noise, 23.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, Noise, 43.00 %', ]); // It should have the "descending" SVG. expect(significanceButton).toMatchSnapshot(); @@ -1121,32 +1126,32 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio // Sort by Effect Size (%) descending const effectSizeButton = screen.getByRole('button', { - name: /CLES \(%\).*sort/, + name: /CLES.*sort/, }); await user.click(effectSizeButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: spam', - ' - Windows 10, -, , -, , 100.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', ' rev: tictactoe', - ' - Windows 10, -, , 0.8, , 99.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', + ' - Windows 10, -, , 0.8, Real, 99.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, Noise, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, Noise, 44.00 %', + ' - Windows 10, -2.40%, , 0.8, Real, 49.00 %', 'a11yr aria.html opt e10s fission stylo webrender', ' rev: spam', - ' - Windows 10, -, , 1.2, , 99.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', + ' - Windows 10, -, , 1.2, Real, 99.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, Noise, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, Noise, 44.00 %', + ' - Windows 10, -2.40%, , 1.2, Real, 49.00 %', ' rev: tictactoe', - ' - Windows 10, -, , 2, , 98.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', + ' - Windows 10, -, , 2, Real, 98.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, Noise, 23.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, Noise, 43.00 %', + ' - Windows 10, -2.40%, , 2, Real, 48.00 %', ]); expect(effectSizeButton).toMatchSnapshot(); @@ -1155,46 +1160,46 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio // Sort by Effect Size (%) ascending await user.click(effectSizeButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: spam', - ' - Windows 10, -2.401 %, , -, , 50.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Windows 10, -, , -, , 100.00 %', + ' - Windows 10, -2.40%, , -, Real, 50.00 %', + ' - Linux 18.04, +1.85%, Regression, -, Noise, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, Noise, 25.00 %', + ' - Windows 10, -, , -, Real, 100.00 %', ' rev: tictactoe', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', - ' - Windows 10, -, , 0.8, , 99.00 %', + ' - Windows 10, -2.40%, , 0.8, Real, 49.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, Noise, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, Noise, 24.00 %', + ' - Windows 10, -, , 0.8, Real, 99.00 %', 'a11yr aria.html opt e10s fission stylo webrender', ' rev: spam', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', - ' - Windows 10, -, , 1.2, , 99.00 %', + ' - Windows 10, -2.40%, , 1.2, Real, 49.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, Noise, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, Noise, 24.00 %', + ' - Windows 10, -, , 1.2, Real, 99.00 %', ' rev: tictactoe', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', - ' - Windows 10, -, , 2, , 98.00 %', + ' - Windows 10, -2.40%, , 2, Real, 48.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, Noise, 43.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, Noise, 23.00 %', + ' - Windows 10, -, , 2, Real, 98.00 %', ]); expect(effectSizeButton).toMatchSnapshot(); // It should be persisted in the URL expectParameterToHaveValue('sort', 'effects|asc'); - // Sort by MD(%) descending + // Sort by Δ Median descending const medianDiffButton = screen.getByRole('button', { - name: /MD \(%\).*sort/, + name: /Δ Median.*sort/, }); await user.click(medianDiffButton); - expect(summarizeVisibleRows('mann-whitney-u')).toMatchSnapshot(); + expect(summarizeVisibleRows('mann-whitney-u', true)).toMatchSnapshot(); expect(medianDiffButton).toMatchSnapshot(); expectParameterToHaveValue('sort', 'median-diff|desc'); // Sort by MD(%) ascending await user.click(medianDiffButton); - expect(summarizeVisibleRows('mann-whitney-u')).toMatchSnapshot(); + expect(summarizeVisibleRows('mann-whitney-u', true)).toMatchSnapshot(); expect(medianDiffButton).toMatchSnapshot(); expectParameterToHaveValue('sort', 'median-diff|asc'); }); @@ -1248,3 +1253,326 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio }); }); }); + +describe('Advanced-columns toggle for mann-whitney-u testVersion', () => { + it('shows Magnitude but hides CD/CLES/Sig in the simplified (default) view', async () => { + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); + await screen.findByText('a11yr'); + + const header = screen.getByTestId('table-header'); + // Only Magnitude is shown in the simplified view; CD/CLES/Sig are all + // advanced columns and hidden by default. + expect(header.querySelector('.magnitude-header')).toBeTruthy(); + expect(header.querySelector('.significance-header')).toBeFalsy(); + expect(header.querySelector('.delta-header')).toBeFalsy(); + expect(header.querySelector('.effects-header')).toBeFalsy(); + }); + + it('reveals CD/CLES/Sig and hides Magnitude when advanced columns are enabled', async () => { + enableAdvancedColumns(); + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); + await screen.findByText('a11yr'); + + const header = screen.getByTestId('table-header'); + expect(header.querySelector('.delta-header')).toBeTruthy(); + expect(header.querySelector('.effects-header')).toBeTruthy(); + expect(header.querySelector('.significance-header')).toBeTruthy(); + expect(header.querySelector('.magnitude-header')).toBeFalsy(); + }); + + it('can filter on the Magnitude column', async () => { + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); + await screen.findByText('a11yr'); + expect(summarizeTableFiltersFromUrl()).toEqual({}); + + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + await clickMenuItem(user, 'Magnitude', /Select only.*Negligible/); + expect(summarizeTableFiltersFromUrl()).toEqual({ + magnitude: ['negligible'], + }); + }); + + it('toggles Cliff’s Delta and CLES independently from the Advanced columns dropdown', async () => { + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); + await screen.findByText('a11yr'); + + const header = () => screen.getByTestId('table-header'); + // Simplified default: neither advanced column. + expect(header().querySelector('.delta-header')).toBeFalsy(); + expect(header().querySelector('.effects-header')).toBeFalsy(); + + // Open the dropdown and enable Cliff's Delta only. + await user.click( + screen.getByRole('combobox', { name: 'Advanced options' }), + ); + await user.click(screen.getByRole('option', { name: "Cliff's Delta" })); + expect(header().querySelector('.delta-header')).toBeTruthy(); + expect(header().querySelector('.effects-header')).toBeFalsy(); + + // Enable CLES too — both show. + await user.click(screen.getByRole('option', { name: 'CLES' })); + expect(header().querySelector('.delta-header')).toBeTruthy(); + expect(header().querySelector('.effects-header')).toBeTruthy(); + + // Turn Cliff's Delta back off — only CLES remains. + await user.click(screen.getByRole('option', { name: "Cliff's Delta" })); + expect(header().querySelector('.delta-header')).toBeFalsy(); + expect(header().querySelector('.effects-header')).toBeTruthy(); + }); + + it('shows the advanced columns named in the advanced_columns URL param', async () => { + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender( + testCompareMannWhitneyData, + 'test_version=mann-whitney-u&advanced_columns=cliffs_delta', + ); + await screen.findByText('a11yr'); + + const header = screen.getByTestId('table-header'); + expect(header.querySelector('.delta-header')).toBeTruthy(); + expect(header.querySelector('.effects-header')).toBeFalsy(); + }); + + it('persists the advanced-column selection to the advanced_columns URL param', async () => { + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); + await screen.findByText('a11yr'); + + const advancedParam = () => + new URLSearchParams(window.location.search).get('advanced_columns'); + expect(advancedParam()).toBeNull(); + + await user.click( + screen.getByRole('combobox', { name: 'Advanced options' }), + ); + await user.click(screen.getByRole('option', { name: "Cliff's Delta" })); + expect(advancedParam()).toBe('cliffs_delta'); + + await user.click(screen.getByRole('option', { name: 'CLES' })); + expect(advancedParam()).toBe('cliffs_delta,cles'); + + // Turning a column off updates the param; turning the last one off removes it. + await user.click(screen.getByRole('option', { name: "Cliff's Delta" })); + expect(advancedParam()).toBe('cles'); + + await user.click(screen.getByRole('option', { name: 'CLES' })); + expect(advancedParam()).toBeNull(); + }); + + it('groups the dropdown into Advanced Columns and Advanced expanded row details sections', async () => { + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); + await screen.findByText('a11yr'); + + await user.click( + screen.getByRole('combobox', { name: 'Advanced options' }), + ); + + // Both group headers and one option from each group are present. + expect(screen.getByText('Advanced Columns')).toBeInTheDocument(); + expect( + screen.getByText('Advanced expanded row details'), + ).toBeInTheDocument(); + expect( + screen.getByRole('option', { name: "Cliff's Delta" }), + ).toBeInTheDocument(); + expect( + screen.getByRole('option', { name: 'Statistics table' }), + ).toBeInTheDocument(); + }); + + it('seeds the expanded-row selection from the advanced_expanded URL param', async () => { + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender( + testCompareMannWhitneyData, + 'test_version=mann-whitney-u&advanced_expanded=stats_table', + ); + await screen.findByText('a11yr'); + + await user.click( + screen.getByRole('combobox', { name: 'Advanced options' }), + ); + + // The seeded option is checked; an unseeded one is not. + expect( + screen.getByRole('option', { name: 'Statistics table' }), + ).toHaveAttribute('aria-selected', 'true'); + expect( + screen.getByRole('option', { name: 'Data warnings' }), + ).toHaveAttribute('aria-selected', 'false'); + }); + + it('persists the expanded-row selection to the advanced_expanded URL param', async () => { + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); + await screen.findByText('a11yr'); + + const expandedParam = () => + new URLSearchParams(window.location.search).get('advanced_expanded'); + expect(expandedParam()).toBeNull(); + + await user.click( + screen.getByRole('combobox', { name: 'Advanced options' }), + ); + await user.click(screen.getByRole('option', { name: 'Statistics table' })); + expect(expandedParam()).toBe('stats_table'); + + await user.click(screen.getByRole('option', { name: 'Data warnings' })); + expect(expandedParam()).toBe('stats_table,warnings'); + + // Turning the columns off leaves the expanded-row param untouched. + await user.click(screen.getByRole('option', { name: 'Statistics table' })); + expect(expandedParam()).toBe('warnings'); + + await user.click(screen.getByRole('option', { name: 'Data warnings' })); + expect(expandedParam()).toBeNull(); + }); + + it('toasts when an expanded-row option is added, but not when removed', async () => { + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); + await screen.findByText('a11yr'); + + await user.click( + screen.getByRole('combobox', { name: 'Advanced options' }), + ); + await user.click(screen.getByRole('option', { name: 'Statistics table' })); + expect( + await screen.findByText(/Statistics table added to the expanded rows/i), + ).toBeInTheDocument(); + + // Turning it back off should NOT toast. + await user.click(screen.getByRole('option', { name: 'Statistics table' })); + expect( + screen.queryByText(/removed from the expanded rows/i), + ).not.toBeInTheDocument(); + }); +}); + +describe('cookie persistence vs. shareable URLs', () => { + it('seeds filters from cookies and marks the URL initialized on a fresh URL', async () => { + document.cookie = 'perfcompare_filter_status=regression; path=/'; + const { testCompareData } = getTestData(); + setupAndRender(testCompareData, 'test_version=student-t'); + + await screen.findByText('a11yr'); + + // The remembered cookie is applied to the view... + expect(summarizeVisibleRows()).toEqual([ + 'a11yr dhtml.html spam opt e10s fission stylo webrender', + ' - Linux 18.04, Regression, 1.85 %, Medium', + ]); + // ...and materialised into the URL, which is now marked initialized so the + // link reproduces this exact view for anyone. + expect(summarizeTableFiltersFromUrl()).toEqual({ status: ['regression'] }); + expect(new URLSearchParams(window.location.search).get('initialized')).toBe( + '1', + ); + }); + + it('ignores cookies when the URL is already initialized', async () => { + // A different viewer's cookie must not change what an initialized (shared) + // URL displays. + document.cookie = 'perfcompare_filter_status=regression; path=/'; + const { testCompareData } = getTestData(); + setupAndRender(testCompareData, 'test_version=student-t&initialized=1'); + + await screen.findByText('a11yr'); + + // Cookie is ignored: every status stays visible. + expect(summarizeVisibleRows()).toEqual([ + 'a11yr dhtml.html spam opt e10s fission stylo webrender', + ' - Linux 18.04, Regression, 1.85 %, Medium', + ' - macOS 10.15, Improvement, 1.08 %, Low', + ' - Windows 10, -, -24 %, -', + ' - Windows 10, -, -2.4 %, High', + ]); + // ...and the cookie is not written into the URL. + expect(summarizeTableFiltersFromUrl()).toEqual({}); + }); + + it('keeps the initialized marker after toggling a filter', async () => { + const { testCompareData } = getTestData(); + setupAndRender(testCompareData, 'test_version=student-t'); + + await screen.findByText('a11yr'); + + const user = userEvent.setup({ + advanceTimers: jest.advanceTimersByTime, + }); + await clickMenuItem(user, 'Status', /No changes/); + + expect(summarizeTableFiltersFromUrl()).toEqual({ + status: ['improvement', 'regression'], + }); + expect(new URLSearchParams(window.location.search).get('initialized')).toBe( + '1', + ); + }); + + it('keeps the initialized marker and seeded filters after a search-term change', async () => { + document.cookie = 'perfcompare_filter_status=regression; path=/'; + const { testCompareData } = getTestData(); + setupAndRender(testCompareData, 'test_version=student-t'); + + await screen.findByText('a11yr'); + + // Seeded from the cookie and marked initialized. + expect(summarizeTableFiltersFromUrl()).toEqual({ status: ['regression'] }); + expect(new URLSearchParams(window.location.search).get('initialized')).toBe( + '1', + ); + + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + // Submit with Enter so the write happens immediately (bypasses the input's + // debounce, which fake timers don't flush after typing). + await user.type( + screen.getByPlaceholderText('Filter results'), + 'linux{Enter}', + ); + + // The search term is written, and the out-of-band params survive. + const params = new URLSearchParams(window.location.search); + expect(params.get('search')).toBe('linux'); + expect(params.get('initialized')).toBe('1'); + expect(params.get('filter_status')).toBe('regression'); + }); + + it('keeps the initialized marker and seeded filters after a test-version change', async () => { + document.cookie = 'perfcompare_filter_status=regression; path=/'; + const { testCompareData } = getTestData(); + setupAndRender(testCompareData, 'test_version=student-t'); + + await screen.findByText('a11yr'); + expect(new URLSearchParams(window.location.search).get('initialized')).toBe( + '1', + ); + + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + await user.click( + screen.getByRole('combobox', { name: 'Stats Test Version' }), + ); + await user.click( + await screen.findByRole('option', { name: 'Mann-Whitney-U' }), + ); + + // The test version changes (a router navigation), and the marker + seeded + // filter ride along instead of being dropped. + await waitFor(() => { + const params = new URLSearchParams(window.location.search); + expect(params.get('test_version')).toBe('mann-whitney-u'); + expect(params.get('initialized')).toBe('1'); + expect(params.get('filter_status')).toBe('regression'); + }); + }); +}); diff --git a/src/__tests__/CompareResults/ResultsView.test.tsx b/src/__tests__/CompareResults/ResultsView.test.tsx index 9d6bb7f31..ffe1101b4 100644 --- a/src/__tests__/CompareResults/ResultsView.test.tsx +++ b/src/__tests__/CompareResults/ResultsView.test.tsx @@ -15,7 +15,7 @@ import type { Framework } from '../../types/types'; import { fftkde } from '../../utils/kde.js'; import { getLocationOrigin } from '../../utils/location'; import getTestData from '../utils/fixtures'; -import { renderWithRouter, screen, waitFor } from '../utils/test-utils'; +import { renderWithRouter, screen, waitFor, within } from '../utils/test-utils'; function renderWithRoute(component: ReactElement) { const { testCompareData, testData } = getTestData(); @@ -345,10 +345,8 @@ describe('Results View', () => { results: [testData[0]], }); - jest.spyOn(window, 'alert').mockImplementation(); - const mockedWindowAlert = window.alert as jest.Mock; - jest.spyOn(window, 'open').mockImplementation(); - const mockedWindowOpen = window.open as jest.Mock; + const mockedWindowAlert = jest.spyOn(window, 'alert').mockImplementation(); + const mockedWindowOpen = jest.spyOn(window, 'open').mockImplementation(); renderWithRouter( <ResultsView title={Strings.metaData.pageTitle.results} />, @@ -375,7 +373,7 @@ describe('Results View', () => { await user.click(retriggerButton); await user.click(await screen.findByRole('button', { name: /Sign in/ })); - let windowOpenUrlString = mockedWindowOpen.mock.lastCall[0] as string; + let windowOpenUrlString = mockedWindowOpen.mock.lastCall![0] as string; let windowOpenUrl = new URL(windowOpenUrlString); expect(sessionStorage.requestState).toBe( windowOpenUrl.searchParams.get('state'), @@ -385,7 +383,7 @@ describe('Results View', () => { // Test requesting an authorization code from Taskcluster staging URL window.location.hash = 'taskcluster-staging'; await user.click(retriggerButton); - windowOpenUrlString = mockedWindowOpen.mock.lastCall[0] as string; + windowOpenUrlString = mockedWindowOpen.mock.lastCall![0] as string; windowOpenUrl = new URL(windowOpenUrlString); expect(sessionStorage.requestState).toBe( windowOpenUrl.searchParams.get('state'), @@ -566,4 +564,41 @@ describe('Results View', () => { expect(screen.queryAllByTestId(/ExpandLessIcon/)).toHaveLength(0); }); }); + + it('shows the "How to read the results" panel by default and lets the user dismiss it', async () => { + renderWithRoute(<ResultsView title={Strings.metaData.pageTitle.results} />); + await screen.findByText('a11yr'); + + // Shown by default. + const panel = screen.getByTestId('how-to-read-results'); + expect(panel).toBeInTheDocument(); + + // Dismiss via the panel's close button (scoped: the MWU warning banner + // also has a close button). + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + await user.click(within(panel).getByRole('button', { name: /close/i })); + expect(screen.queryByTestId('how-to-read-results')).not.toBeInTheDocument(); + + // The "How to read the results" checkbox brings it back. + await user.click( + screen.getByRole('checkbox', { name: /How to read the results/i }), + ); + expect(screen.getByTestId('how-to-read-results')).toBeInTheDocument(); + }); + + it('shows the Mann-Whitney-U warning banner and lets the user dismiss it with the X', async () => { + renderWithRoute(<ResultsView title={Strings.metaData.pageTitle.results} />); + await screen.findByText('a11yr'); + + // Shown by default (the default test version is Mann-Whitney-U). + const warning = await screen.findByText(/experimental stage/i); + const banner = warning.closest('.MuiAlert-root') as HTMLElement; + expect(banner).toBeInTheDocument(); + + // Dismiss via the banner's close button. + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + await user.click(within(banner).getByRole('button', { name: /close/i })); + + expect(screen.queryByText(/experimental stage/i)).not.toBeInTheDocument(); + }); }); diff --git a/src/__tests__/CompareResults/RevisionRow.test.tsx b/src/__tests__/CompareResults/RevisionRow.test.tsx index ae86e4950..93ddd8e2a 100644 --- a/src/__tests__/CompareResults/RevisionRow.test.tsx +++ b/src/__tests__/CompareResults/RevisionRow.test.tsx @@ -11,7 +11,12 @@ import { useSubtestRegressionCount } from '../../hooks/useSubtestRegressionCount import { CompareResultsItem, MannWhitneyResultsItem } from '../../types/state'; import { Platform } from '../../types/types'; import getTestData from '../utils/fixtures'; -import { screen, renderWithRouter } from '../utils/test-utils'; +import { + screen, + renderWithRouter, + enableAdvancedColumns, + enableExpandedRowOptions, +} from '../utils/test-utils'; jest.mock('../../hooks/useSubtestRegressionCount'); const mockUseSubtestRegressionCount = useSubtestRegressionCount as jest.Mock; @@ -163,6 +168,10 @@ describe('Subtest count pills', () => { }); describe('Expanded row', () => { + // Several tests assert the (advanced) MWU expanded-row components, which are + // hidden by default; enable them. No-op for Student-T expanded rows. + beforeEach(() => enableExpandedRowOptions()); + it('should display "Show 39 more" and "Show less" for base runs when row is expanded', async () => { const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); const { testCompareDataWithReplicatesMultipleValues: rowData } = @@ -427,6 +436,7 @@ describe('Expanded row', () => { }); it('should display mean for base or new in row headers for mann-whitney-u testVersion', async () => { + enableAdvancedColumns(); const { testCompareMannWhitneyData: rowData } = getTestData(); renderWithRoute( <RevisionRow @@ -541,7 +551,7 @@ describe('Expanded row', () => { }; } - it('shows dash when neither distribution is normal', async () => { + it('shows value with warning icon when neither distribution is normal', async () => { const result = makeResult(tooFewRuns, tooFewRuns); expect(isDistributionNormal(result)).toBe(false); renderWithRoute( @@ -555,7 +565,10 @@ describe('Expanded row', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).toHaveTextContent('-'); + // The median difference is rank-based, so it's shown even for non-normal + // data; only a warning icon flags the shape. + expect(roles[4]).toHaveTextContent('%'); + expect(roles[4].querySelector('svg[role="img"]')).toBeTruthy(); }); it('shows value with warning icon when only one distribution is normal', async () => { @@ -572,7 +585,7 @@ describe('Expanded row', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).not.toHaveTextContent('-'); + expect(roles[4]).toHaveTextContent('%'); expect(roles[4].querySelector('svg[role="img"]')).toBeTruthy(); }); @@ -590,7 +603,7 @@ describe('Expanded row', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).not.toHaveTextContent('-'); + expect(roles[4]).toHaveTextContent('%'); expect(roles[4].querySelector('svg[role="img"]')).toBeFalsy(); }); }); diff --git a/src/__tests__/CompareResults/RevisionRowExpandable.test.tsx b/src/__tests__/CompareResults/RevisionRowExpandable.test.tsx index 542c0a22a..57b62d437 100644 --- a/src/__tests__/CompareResults/RevisionRowExpandable.test.tsx +++ b/src/__tests__/CompareResults/RevisionRowExpandable.test.tsx @@ -1,11 +1,16 @@ import { ReactElement } from 'react'; import fetchMock from '@fetch-mock/jest'; +import userEvent from '@testing-library/user-event'; import { loader } from '../../components/CompareResults/loader'; import RevisionRowExpandable from '../../components/CompareResults/RevisionRowExpandable'; import getTestData from '../utils/fixtures'; -import { screen, renderWithRouter } from '../utils/test-utils'; +import { + screen, + renderWithRouter, + enableExpandedRowOptions, +} from '../utils/test-utils'; function renderWithRoute(component: ReactElement) { fetchMock @@ -62,6 +67,9 @@ describe('RevisionRowExpandable for student-t testVersion', () => { }); describe('RevisionRowExpandable for mann-whitney-u testVersion', () => { + // These assert the (advanced) expanded-row components, hidden by default. + beforeEach(() => enableExpandedRowOptions()); + it('should display warnings', async () => { const { mockMannWhitneyResultData } = getTestData(); @@ -73,15 +81,11 @@ describe('RevisionRowExpandable for mann-whitney-u testVersion', () => { />, ); - const expectedWarning1 = - 'Less than 2 datapoints or no standard variance for a meaningful fit Kernel Density Estimator (KDE) with an ISJ bandwidth to Base.'; const shapiroWarning = 'Shapiro-Wilk test cannot be run on Base with fewer than 3 data points.'; const shapiroWarning2 = 'Shapiro-Wilk test cannot be run on New with fewer than 3 data points.'; - const warning1 = await screen.findByText(expectedWarning1); - expect(warning1).toBeInTheDocument(); const swWarning = await screen.findByText(shapiroWarning); expect(swWarning).toBeInTheDocument(); const swWarning2 = await screen.findByText(shapiroWarning2); @@ -151,3 +155,100 @@ describe('RevisionRowExpandable for mann-whitney-u testVersion', () => { expect(goodFit).toBeInTheDocument(); }); }); + +describe('RevisionRowExpandable simplified Mann-Whitney-U view', () => { + // Text unique to each advanced expanded-row component, used to assert whether + // that component is currently rendered. + const EFFECT_SIZE_TEXT = /Effect Size:/; + const STATS_TABLE_TEXT = /Normality Test/; + const WARNINGS_TEXT = /Shapiro-Wilk test cannot be run/; + const MODES_LABEL = 'Mode-by-mode breakdown'; + + function renderMwuRow() { + const { mockMannWhitneyResultData } = getTestData(); + renderWithRoute( + <RevisionRowExpandable + result={mockMannWhitneyResultData} + testVersion='mann-whitney-u' + id='mwu-simple' + />, + ); + } + + it('shows the how-to-read blurb in a graph tooltip and hides every advanced component by default', async () => { + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + renderMwuRow(); + + // The how-to-read blurb is a tooltip on the graph's info icon. + expect( + screen.queryByText(/how the Base and New results are distributed/i), + ).not.toBeInTheDocument(); + await user.hover(await screen.findByLabelText('How to read this graph')); + expect( + await screen.findByText(/how the Base and New results are distributed/i), + ).toBeInTheDocument(); + + // None of the advanced (checkbox-gated) components render by default. + expect(screen.queryByText(EFFECT_SIZE_TEXT)).not.toBeInTheDocument(); + expect(screen.queryByText(STATS_TABLE_TEXT)).not.toBeInTheDocument(); + expect(screen.queryByText(WARNINGS_TEXT)).not.toBeInTheDocument(); + expect(screen.queryByLabelText(MODES_LABEL)).not.toBeInTheDocument(); + }); + + it('reveals only the effect size component when that option is on', async () => { + enableExpandedRowOptions({ effectSize: true }); + renderMwuRow(); + + expect(await screen.findByText(EFFECT_SIZE_TEXT)).toBeInTheDocument(); + expect(screen.queryByText(STATS_TABLE_TEXT)).not.toBeInTheDocument(); + expect(screen.queryByText(WARNINGS_TEXT)).not.toBeInTheDocument(); + }); + + it('reveals only the statistics table when that option is on', async () => { + enableExpandedRowOptions({ statsTable: true }); + renderMwuRow(); + + expect(await screen.findByText(STATS_TABLE_TEXT)).toBeInTheDocument(); + expect(screen.queryByText(EFFECT_SIZE_TEXT)).not.toBeInTheDocument(); + expect(screen.queryByText(WARNINGS_TEXT)).not.toBeInTheDocument(); + }); + + it('reveals only the data warnings when that option is on', async () => { + enableExpandedRowOptions({ warnings: true }); + renderMwuRow(); + + // Base and New each contribute a Shapiro-Wilk warning. + expect((await screen.findAllByText(WARNINGS_TEXT)).length).toBeGreaterThan( + 0, + ); + expect(screen.queryByText(EFFECT_SIZE_TEXT)).not.toBeInTheDocument(); + expect(screen.queryByText(STATS_TABLE_TEXT)).not.toBeInTheDocument(); + }); + + it('shows the graph mode controls (valley-depth slider + Show modes) by default, independent of the Mode analysis option', async () => { + renderMwuRow(); + + // The controls live on the graph and are available in the simplified view + // without enabling the "Mode analysis" expanded-row option. + expect( + await screen.findByRole('slider', { name: /valley depth threshold/i }), + ).toBeInTheDocument(); + expect( + screen.getByRole('checkbox', { name: /show modes/i }), + ).toBeInTheDocument(); + }); + + it('shows a placeholder when Mode analysis is on but no breakdown is available', async () => { + // The mock is a sparse/unimodal comparison, so no mode-by-mode breakdown is + // produced; the cell should surface a placeholder rather than stay empty. + enableExpandedRowOptions({ modes: true }); + renderMwuRow(); + + expect( + await screen.findByText(/No mode analysis available/i), + ).toBeInTheDocument(); + expect( + screen.queryByLabelText('Mode-by-mode breakdown'), + ).not.toBeInTheDocument(); + }); +}); diff --git a/src/__tests__/CompareResults/SubtestsResultsView.test.tsx b/src/__tests__/CompareResults/SubtestsResultsView.test.tsx index 87e1b9081..1607c4b5c 100644 --- a/src/__tests__/CompareResults/SubtestsResultsView.test.tsx +++ b/src/__tests__/CompareResults/SubtestsResultsView.test.tsx @@ -10,11 +10,22 @@ import type { CombinedResultsItemType } from '../../types/state'; import { TestVersion } from '../../types/types'; import { getLocationOrigin } from '../../utils/location'; import getTestData from '../utils/fixtures'; -import { renderWithRouter, screen } from '../utils/test-utils'; +import { + renderWithRouter, + screen, + enableAdvancedColumns, + enableExpandedRowOptions, +} from '../utils/test-utils'; jest.mock('../../utils/location'); const mockedGetLocationOrigin = getLocationOrigin as jest.Mock; +// The Mann-Whitney-U expanded row hides its statistical components (stats +// table, warnings, effect size, modes) behind "Advanced options" by default. +// These tests assert on those components, so enable them everywhere here. This +// is a no-op for rows that aren't expanded and for the Student-T layout. +beforeEach(() => enableExpandedRowOptions()); + const setup = ({ element, route, @@ -48,7 +59,7 @@ const setup = ({ // This handy function parses the results page and returns an array of visible // rows. It makes it easy to assert visible rows when filtering them in a // user-friendly way without using snapshots. -function summarizeVisibleRows(testVersion?: TestVersion) { +function summarizeVisibleRows(testVersion?: TestVersion, advanced = false) { const rows = screen.getAllByRole('row'); const result = []; for (const row of rows) { @@ -59,10 +70,19 @@ function summarizeVisibleRows(testVersion?: TestVersion) { } const rowClasses = testVersion === 'mann-whitney-u' - ? ['.median-diff', '.delta', '.significance', '.effects'] + ? advanced + ? ['.median-diff', '.delta', '.significance', '.effects'] + : ['.median-diff', '.status-hint', '.magnitude', '.significance'] : ['.delta', '.confidence']; const rowString = rowClasses - .map((selector) => row.querySelector(selector)?.textContent.trim()) + .map((selector) => { + const cell = row.querySelector(selector); + if (!cell) return undefined; + // Strip icon <title> text (e.g. the median-diff normality warning). + const clone = cell.cloneNode(true) as HTMLElement; + clone.querySelectorAll('svg').forEach((svg) => svg.remove()); + return clone.textContent?.trim(); + }) .join(', '); result.push(`${subtest}: ${rowString}`); } @@ -141,10 +161,8 @@ describe('SubtestsResultsView Component Tests', () => { const { subtestsResult } = getTestData(); const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); - jest.spyOn(window, 'alert').mockImplementation(); - const mockedWindowAlert = window.alert as jest.Mock; - jest.spyOn(window, 'open').mockImplementation(); - const mockedWindowOpen = window.open as jest.Mock; + const mockedWindowAlert = jest.spyOn(window, 'alert').mockImplementation(); + const mockedWindowOpen = jest.spyOn(window, 'open').mockImplementation(); setup({ element: ( @@ -172,7 +190,7 @@ describe('SubtestsResultsView Component Tests', () => { await user.click(retriggerButton); await user.click(await screen.findByRole('button', { name: /Sign in/ })); - let windowOpenUrlString = mockedWindowOpen.mock.lastCall[0] as string; + let windowOpenUrlString = mockedWindowOpen.mock.lastCall![0] as string; let windowOpenUrl = new URL(windowOpenUrlString); expect(sessionStorage.requestState).toBe( windowOpenUrl.searchParams.get('state'), @@ -182,7 +200,7 @@ describe('SubtestsResultsView Component Tests', () => { // Test requesting an authorization code from Taskcluster staging URL window.location.hash = 'taskcluster-staging'; await user.click(retriggerButton); - windowOpenUrlString = mockedWindowOpen.mock.lastCall[0] as string; + windowOpenUrlString = mockedWindowOpen.mock.lastCall![0] as string; windowOpenUrl = new URL(windowOpenUrlString); expect(sessionStorage.requestState).toBe( windowOpenUrl.searchParams.get('state'), @@ -499,6 +517,11 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( }); describe('table sorting', () => { + // These sort by CD and Significance, which are advanced-only columns. + beforeEach(() => { + enableAdvancedColumns(); + }); + async function setupForSorting({ extraParameters, }: Partial<{ @@ -526,12 +549,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( it('can sort the table and persist the information to the URL of mann-whitney-u values', async () => { await setupForSorting(); // Initial view (alphabetical ordered, even if "sort by subtests" isn't specified - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'browser.html: +1.14%, -0.04, Noise, 15.00%', + 'dhtml.html: +1.14%, 0.02, Real, 60.00%', + 'improvement.html: +1.14%, -0.05, Real, 50.00%', + 'regression.html: +1.14%, 0.12, Real, 25.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', ]); // Sort by Delta @@ -541,12 +564,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( expect(window.location.search).not.toContain('sort='); // Sort descending await user.click(deltaButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'regression.html: +1.14%, 0.12, Real, 25.00%', + 'improvement.html: +1.14%, -0.05, Real, 50.00%', + 'browser.html: +1.14%, -0.04, Noise, 15.00%', + 'dhtml.html: +1.14%, 0.02, Real, 60.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', ]); // It should have the "descending" SVG. @@ -556,12 +579,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( // Sort ascending await user.click(deltaButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'dhtml.html: +1.14%, 0.02, Real, 60.00%', + 'browser.html: +1.14%, -0.04, Noise, 15.00%', + 'improvement.html: +1.14%, -0.05, Real, 50.00%', + 'regression.html: +1.14%, 0.12, Real, 25.00%', ]); // It should have the "ascending" SVG. expect(deltaButton).toMatchSnapshot(); @@ -573,12 +596,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( name: /Sig.*sort/, }); await user.click(significanceButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'browser.html: +1.14%, -0.04, Noise, 15.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'dhtml.html: +1.14%, 0.02, Real, 60.00%', + 'regression.html: +1.14%, 0.12, Real, 25.00%', + 'improvement.html: +1.14%, -0.05, Real, 50.00%', ]); // It should have the "no sort" SVG. expect(deltaButton).toMatchSnapshot(); @@ -589,26 +612,26 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( // Sort by Significance ascending await user.click(significanceButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'improvement.html: +1.14%, -0.05, Real, 50.00%', + 'regression.html: +1.14%, 0.12, Real, 25.00%', + 'dhtml.html: +1.14%, 0.02, Real, 60.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'browser.html: +1.14%, -0.04, Noise, 15.00%', ]); expectParameterToHaveValue('sort', 'significance|asc'); // Sort by Effect Size descending const effectButton = screen.getByRole('button', { - name: /CLES \(%\).*sort/, + name: /CLES.*sort/, }); await user.click(effectButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'browser.html: +1.14%, -0.04, Noise, 15.00%', + 'regression.html: +1.14%, 0.12, Real, 25.00%', + 'dhtml.html: +1.14%, 0.02, Real, 60.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'improvement.html: +1.14%, -0.05, Real, 50.00%', ]); // It should have the "descending" SVG. @@ -618,12 +641,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( // Sort by Effect Size ascending await user.click(effectButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'improvement.html: +1.14%, -0.05, Real, 50.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'dhtml.html: +1.14%, 0.02, Real, 60.00%', + 'regression.html: +1.14%, 0.12, Real, 25.00%', + 'browser.html: +1.14%, -0.04, Noise, 15.00%', ]); expectParameterToHaveValue('sort', 'effects|asc'); }); @@ -631,12 +654,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( it('initializes the sort from the URL at load time for an ascending sort', async () => { await setupForSorting({ extraParameters: 'sort=delta|asc' }); await screen.findByText('dhtml.html'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'dhtml.html: +1.14%, 0.02, Real, 60.00%', + 'browser.html: +1.14%, -0.04, Noise, 15.00%', + 'improvement.html: +1.14%, -0.05, Real, 50.00%', + 'regression.html: +1.14%, 0.12, Real, 25.00%', ]); // It should have the "ascending" SVG. expect(screen.getByRole('button', { name: /CD/ })).toMatchSnapshot(); @@ -645,12 +668,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( it('initializes the sort from the URL at load time for an implicit descending sort', async () => { await setupForSorting({ extraParameters: 'sort=delta' }); await screen.findByText('dhtml.html'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'regression.html: +1.14%, 0.12, Real, 25.00%', + 'improvement.html: +1.14%, -0.05, Real, 50.00%', + 'browser.html: +1.14%, -0.04, Noise, 15.00%', + 'dhtml.html: +1.14%, 0.02, Real, 60.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', ]); // It should have the "descending" SVG. expect(screen.getByRole('button', { name: /CD/ })).toMatchSnapshot(); @@ -658,12 +681,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( it('initializes the sort from the URL at load time for a descending sort', async () => { await setupForSorting({ extraParameters: 'sort=delta|desc' }); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'regression.html: +1.14%, 0.12, Real, 25.00%', + 'improvement.html: +1.14%, -0.05, Real, 50.00%', + 'browser.html: +1.14%, -0.04, Noise, 15.00%', + 'dhtml.html: +1.14%, 0.02, Real, 60.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', ]); // It should have the "descending" SVG. expect(screen.getByRole('button', { name: /CD/ })).toMatchSnapshot(); @@ -732,3 +755,45 @@ describe('SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVers expect(document.body).toMatchSnapshot(); }); }); + +describe('cookie persistence vs. shareable URLs (subtests)', () => { + it('keeps the initialized marker and seeded filters after a search-term change', async () => { + // Regression test: the subtests search handler must build its URL write + // from the live URL, otherwise the cookie-seeded filter/sort and the + // `initialized` marker (written out-of-band on mount) get clobbered. + document.cookie = 'perfcompare_filter_status=regression; path=/'; + const { subtestsResult } = getTestData(); + setup({ + element: ( + <SubtestsResultsView title={Strings.metaData.pageTitle.subtests} /> + ), + route: '/subtests-compare-results/', + search: + '?baseRev=f49863193c13c1def4db2dd3ea9c5d6bd9d517a7&baseRepo=mozilla-central&newRev=2cb6128d7dca8c9a9266b3505d64d55ac1bcc8a8&newRepo=mozilla-central&framework=1&baseParentSignature=4774487&newParentSignature=4774487&test_version=student-t', + subtestsResult, + }); + + // Wait on filter-independent page chrome (the regression filter may hide + // every row, so don't key on a specific subtest). + await screen.findByText('All results'); + + // Seeded from the cookie and marked initialized on mount. + const seeded = new URLSearchParams(window.location.search); + expect(seeded.get('filter_status')).toBe('regression'); + expect(seeded.get('initialized')).toBe('1'); + + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + // Submit with Enter so the write happens immediately (bypasses the input's + // debounce, which fake timers don't flush after typing). + await user.type( + screen.getByPlaceholderText('Filter results'), + 'dhtml{Enter}', + ); + + // The search term is written, and the out-of-band params survive. + const params = new URLSearchParams(window.location.search); + expect(params.get('search')).toBe('dhtml'); + expect(params.get('initialized')).toBe('1'); + expect(params.get('filter_status')).toBe('regression'); + }); +}); diff --git a/src/__tests__/CompareResults/SubtestsRevisionRow.test.tsx b/src/__tests__/CompareResults/SubtestsRevisionRow.test.tsx index d8941e030..9cfef3274 100644 --- a/src/__tests__/CompareResults/SubtestsRevisionRow.test.tsx +++ b/src/__tests__/CompareResults/SubtestsRevisionRow.test.tsx @@ -7,7 +7,12 @@ import { loader } from '../../components/CompareResults/loader'; import SubtestsRevisionRow from '../../components/CompareResults/SubtestsResults/SubtestsRevisionRow'; import { MannWhitneyResultsItem } from '../../types/state'; import getTestData from '../utils/fixtures'; -import { screen, renderWithRouter } from '../utils/test-utils'; +import { + screen, + renderWithRouter, + enableAdvancedColumns, + enableExpandedRowOptions, +} from '../utils/test-utils'; function renderWithRoute(component: ReactElement) { fetchMock @@ -120,6 +125,7 @@ describe('SubtestsRevisionRow Component', () => { }); it('renders subtests results with mann-whitney-u testVersion', async () => { + enableExpandedRowOptions(); const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); const { subtestsResult } = getTestData(); const mockGridTemplateColumns = '1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr'; @@ -141,6 +147,7 @@ describe('SubtestsRevisionRow Component', () => { }); it('renders subtests results defaulting to mann-whitney-u with no testVersion', async () => { + enableExpandedRowOptions(); const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); const { subtestsMannWhitneyResult } = getTestData(); const mockGridTemplateColumns = '1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr'; @@ -178,6 +185,7 @@ describe('SubtestsRevisionRow Component', () => { }); it('should display cliffs delta, significance, and effects size in subtests for mann-whitney-u testVersion', async () => { + enableAdvancedColumns(); const { subtestsMannWhitneyResult } = getTestData(); const mockGridTemplateColumns = '1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr'; renderWithRoute( @@ -194,7 +202,7 @@ describe('SubtestsRevisionRow Component', () => { expect(effects).toHaveTextContent('60.00%'); const significanceCell = roles[8]; - expect(significanceCell?.querySelector('svg')).not.toBeNull(); + expect(significanceCell).toHaveTextContent('Real'); const cliffs_delta = roles[6]?.childNodes[1]; expect(cliffs_delta).toHaveTextContent('0.02'); @@ -213,7 +221,7 @@ describe('SubtestsRevisionRow Component', () => { ); const roles = await screen.findAllByRole('cell'); - const status = roles[5]?.childNodes[0]; + const status = roles[5]?.querySelector('.status-hint'); expect(status).toHaveTextContent('Regression'); expect(status).toHaveClass('status-hint-regression'); }); @@ -231,7 +239,7 @@ describe('SubtestsRevisionRow Component', () => { ); const roles1 = await screen.findAllByRole('cell'); - const status1 = roles1[5]?.childNodes[0]; + const status1 = roles1[5]?.querySelector('.status-hint'); expect(status1).toHaveTextContent('Improvement'); expect(status1).toHaveClass('status-hint-improvement'); }); @@ -253,7 +261,7 @@ describe('SubtestsRevisionRow Component', () => { }; } - it('shows dash when neither distribution is normal', async () => { + it('shows value with warning icon when neither distribution is normal', async () => { renderWithRoute( <SubtestsRevisionRow result={makeResult(tooFewRuns, tooFewRuns)} @@ -263,7 +271,10 @@ describe('SubtestsRevisionRow Component', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).toHaveTextContent('-'); + // The median difference is rank-based, so it's shown even for non-normal + // data; only a warning icon flags the shape. + expect(roles[4]).toHaveTextContent('%'); + expect(roles[4].querySelector('svg[role="img"]')).toBeTruthy(); }); it('shows value with warning icon when only one distribution is normal', async () => { @@ -276,7 +287,7 @@ describe('SubtestsRevisionRow Component', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).not.toHaveTextContent('-'); + expect(roles[4]).toHaveTextContent('%'); expect(roles[4].querySelector('svg[role="img"]')).toBeTruthy(); }); @@ -290,7 +301,7 @@ describe('SubtestsRevisionRow Component', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).not.toHaveTextContent('-'); + expect(roles[4]).toHaveTextContent('%'); expect(roles[4].querySelector('svg[role="img"]')).toBeFalsy(); }); }); diff --git a/src/__tests__/CompareResults/__snapshots__/OverTimeResultsView.test.tsx.snap b/src/__tests__/CompareResults/__snapshots__/OverTimeResultsView.test.tsx.snap index dbd059e14..bf33069bd 100644 --- a/src/__tests__/CompareResults/__snapshots__/OverTimeResultsView.test.tsx.snap +++ b/src/__tests__/CompareResults/__snapshots__/OverTimeResultsView.test.tsx.snap @@ -10,343 +10,441 @@ exports[`Results View The table should match snapshot and other elements should class="MuiBox-root css-1rw0zd7" > <div - class="MuiGrid-root MuiGrid-container MuiGrid-direction-xs-row MuiGrid-spacing-xs-2 f1wpas00 css-13620ud-MuiGrid-root" + class="MuiGrid-root MuiGrid-container MuiGrid-direction-xs-row MuiGrid-spacing-xs-2 f1wpas00 results-controls css-13620ud-MuiGrid-root" > <div - class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-md-3 MuiGrid-grid-xs-12 css-11ufmbb-MuiGrid-root" + class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-12 css-16nz7cf-MuiGrid-root" > - <form - aria-label="Search by title, platform, revision or options" - class="MuiBox-root css-1wxqtyp" + <div + class="results-controls-selections MuiBox-root css-1rh9huw" > - <div - class="MuiFormControl-root MuiTextField-root css-q16m8p-MuiFormControl-root-MuiTextField-root" + <label + aria-label="Show the "How to read the results" guide above the table" + class="MuiFormControlLabel-root MuiFormControlLabel-labelPlacementEnd css-1bsjtco-MuiFormControlLabel-root" data-mui-internal-clone-element="true" + > + <span + class="MuiButtonBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall PrivateSwitchBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall Mui-checked MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall css-1nff2up-MuiButtonBase-root-MuiSwitchBase-root-MuiCheckbox-root" + > + <input + checked="" + class="PrivateSwitchBase-input css-12xagqm-MuiSwitchBase-root" + data-indeterminate="false" + type="checkbox" + /> + <svg + aria-hidden="true" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeSmall css-54rgmy-MuiSvgIcon-root" + data-testid="CheckBoxIcon" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" + /> + </svg> + </span> + <span + class="MuiTypography-root MuiTypography-body1 MuiFormControlLabel-label css-n290n7-MuiTypography-root" + > + How to read the results + </span> + </label> + <label + class="MuiFormControlLabel-root MuiFormControlLabel-labelPlacementEnd css-1bsjtco-MuiFormControlLabel-root" + > + <span + class="MuiButtonBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall PrivateSwitchBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall css-1nff2up-MuiButtonBase-root-MuiSwitchBase-root-MuiCheckbox-root" + > + <input + class="PrivateSwitchBase-input css-12xagqm-MuiSwitchBase-root" + data-indeterminate="false" + type="checkbox" + /> + <svg + aria-hidden="true" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeSmall css-54rgmy-MuiSvgIcon-root" + data-testid="CheckBoxOutlineBlankIcon" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z" + /> + </svg> + </span> + <span + class="MuiTypography-root MuiTypography-body1 MuiFormControlLabel-label css-n290n7-MuiTypography-root" + > + Expand all rows + </span> + </label> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-12 css-16nz7cf-MuiGrid-root" + > + <div + class="MuiGrid-root MuiGrid-container MuiGrid-direction-xs-row MuiGrid-spacing-xs-2 results-controls-inputs css-13620ud-MuiGrid-root" + > + <div + class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-md-3 MuiGrid-grid-xs-12 css-11ufmbb-MuiGrid-root" + > + <form + aria-label="Search by title, platform, revision or options" + class="MuiBox-root css-1wxqtyp" + > + <div + class="MuiFormControl-root MuiTextField-root css-q16m8p-MuiFormControl-root-MuiTextField-root" + data-mui-internal-clone-element="true" + > + <div + class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-formControl MuiInputBase-sizeSmall MuiInputBase-adornedStart MuiInputBase-adornedEnd css-1cqjfkd-MuiInputBase-root-MuiOutlinedInput-root" + > + <div + class="MuiInputAdornment-root MuiInputAdornment-positionStart MuiInputAdornment-outlined MuiInputAdornment-sizeSmall css-1nowbqt-MuiInputAdornment-root" + > + <span + aria-hidden="true" + class="notranslate" + > + ​ + </span> + <svg + aria-hidden="true" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-120he73-MuiSvgIcon-root" + data-testid="SearchIcon" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14" + /> + </svg> + </div> + <input + aria-description="Tip: You can search with multiple words (all must match). Use -word to exclude results containing that word." + aria-invalid="false" + aria-label="Search by title, platform, revision or options" + class="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall MuiInputBase-inputAdornedStart MuiInputBase-inputAdornedEnd css-3v3un6-MuiInputBase-input-MuiOutlinedInput-input" + id="_r_d_" + placeholder="Filter results" + type="search" + value="" + /> + <div + class="MuiInputAdornment-root MuiInputAdornment-positionEnd MuiInputAdornment-outlined MuiInputAdornment-sizeSmall css-elo8k2-MuiInputAdornment-root" + > + <button + aria-label="Clear the search input" + class="MuiButtonBase-root MuiIconButton-root MuiIconButton-edgeEnd MuiIconButton-sizeSmall css-13mnts1-MuiButtonBase-root-MuiIconButton-root" + tabindex="0" + type="button" + > + <svg + aria-hidden="true" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-120he73-MuiSvgIcon-root" + data-testid="CloseIcon" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" + /> + </svg> + </button> + </div> + <fieldset + aria-hidden="true" + class="MuiOutlinedInput-notchedOutline css-18p5xg2-MuiNotchedOutlined-root-MuiOutlinedInput-notchedOutline" + > + <legend + class="css-1nf2c5d-MuiNotchedOutlined-root" + > + <span + aria-hidden="true" + class="notranslate" + > + ​ + </span> + </legend> + </fieldset> + </div> + </div> + </form> + </div> + <div + class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-md-2 MuiGrid-grid-xs-6 css-4yvdwt-MuiGrid-root" > <div - class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-formControl MuiInputBase-sizeSmall MuiInputBase-adornedStart MuiInputBase-adornedEnd css-1cqjfkd-MuiInputBase-root-MuiOutlinedInput-root" + class="MuiFormControl-root css-7549ua-MuiFormControl-root" > <div - class="MuiInputAdornment-root MuiInputAdornment-positionStart MuiInputAdornment-outlined MuiInputAdornment-sizeSmall css-1nowbqt-MuiInputAdornment-root" + class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-formControl MuiInputBase-sizeSmall framework-dropdown-select MuiSelect-root css-fcr66i-MuiInputBase-root-MuiOutlinedInput-root-MuiSelect-root" + data-testid="framework-select" > - <span - aria-hidden="true" - class="notranslate" + <div + aria-expanded="false" + aria-haspopup="listbox" + aria-label="Framework" + aria-labelledby="mui-component-select-framework" + class="MuiSelect-select MuiSelect-outlined MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall css-1rcoerw-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiOutlinedInput-input" + id="mui-component-select-framework" + role="combobox" + tabindex="0" > - ​ - </span> + talos + </div> + <input + aria-hidden="true" + aria-invalid="false" + class="MuiSelect-nativeInput css-j0riat-MuiSelect-nativeInput" + name="framework" + tabindex="-1" + value="1" + /> <svg aria-hidden="true" - class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-120he73-MuiSvgIcon-root" - data-testid="SearchIcon" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium MuiSelect-icon MuiSelect-iconOutlined css-h42w4p-MuiSvgIcon-root-MuiNativeSelect-root-MuiSelect-icon" + data-testid="ArrowDropDownIcon" focusable="false" viewBox="0 0 24 24" > <path - d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14" + d="M7 10l5 5 5-5z" /> </svg> - </div> - <input - aria-description="Tip: You can search with multiple words (all must match). Use -word to exclude results containing that word." - aria-invalid="false" - aria-label="Search by title, platform, revision or options" - class="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall MuiInputBase-inputAdornedStart MuiInputBase-inputAdornedEnd css-3v3un6-MuiInputBase-input-MuiOutlinedInput-input" - id="_r_a_" - placeholder="Filter results" - type="search" - value="" - /> - <div - class="MuiInputAdornment-root MuiInputAdornment-positionEnd MuiInputAdornment-outlined MuiInputAdornment-sizeSmall css-elo8k2-MuiInputAdornment-root" - > - <button - aria-label="Clear the search input" - class="MuiButtonBase-root MuiIconButton-root MuiIconButton-edgeEnd MuiIconButton-sizeSmall css-13mnts1-MuiButtonBase-root-MuiIconButton-root" - tabindex="0" - type="button" + <fieldset + aria-hidden="true" + class="MuiOutlinedInput-notchedOutline css-18p5xg2-MuiNotchedOutlined-root-MuiOutlinedInput-notchedOutline" > - <svg - aria-hidden="true" - class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-120he73-MuiSvgIcon-root" - data-testid="CloseIcon" - focusable="false" - viewBox="0 0 24 24" + <legend + class="css-1nf2c5d-MuiNotchedOutlined-root" > - <path - d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" - /> - </svg> - </button> + <span + aria-hidden="true" + class="notranslate" + > + ​ + </span> + </legend> + </fieldset> </div> - <fieldset - aria-hidden="true" - class="MuiOutlinedInput-notchedOutline css-18p5xg2-MuiNotchedOutlined-root-MuiOutlinedInput-notchedOutline" - > - <legend - class="css-1nf2c5d-MuiNotchedOutlined-root" - > - <span - aria-hidden="true" - class="notranslate" - > - ​ - </span> - </legend> - </fieldset> </div> </div> - </form> - </div> - <div - class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-md-2 MuiGrid-grid-xs-6 css-4yvdwt-MuiGrid-root" - > - <div - class="MuiFormControl-root css-7549ua-MuiFormControl-root" - > <div - class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-formControl MuiInputBase-sizeSmall framework-dropdown-select MuiSelect-root css-fcr66i-MuiInputBase-root-MuiOutlinedInput-root-MuiSelect-root" - data-testid="framework-select" + class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-md-2 MuiGrid-grid-xs-6 css-4yvdwt-MuiGrid-root" > <div - aria-expanded="false" - aria-haspopup="listbox" - aria-label="Framework" - aria-labelledby="mui-component-select-framework" - class="MuiSelect-select MuiSelect-outlined MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall css-1hw1663-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiOutlinedInput-input" - id="mui-component-select-framework" - role="combobox" - tabindex="0" - > - talos - </div> - <input - aria-hidden="true" - aria-invalid="false" - class="MuiSelect-nativeInput css-j0riat-MuiSelect-nativeInput" - name="framework" - tabindex="-1" - value="1" - /> - <svg - aria-hidden="true" - class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium MuiSelect-icon MuiSelect-iconOutlined css-h42w4p-MuiSvgIcon-root-MuiNativeSelect-root-MuiSelect-icon" - data-testid="ArrowDropDownIcon" - focusable="false" - viewBox="0 0 24 24" - > - <path - d="M7 10l5 5 5-5z" - /> - </svg> - <fieldset - aria-hidden="true" - class="MuiOutlinedInput-notchedOutline css-18p5xg2-MuiNotchedOutlined-root-MuiOutlinedInput-notchedOutline" + class="MuiFormControl-root css-7549ua-MuiFormControl-root" > - <legend - class="css-1nf2c5d-MuiNotchedOutlined-root" + <div + class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-formControl MuiInputBase-sizeSmall test-version-select MuiSelect-root css-fcr66i-MuiInputBase-root-MuiOutlinedInput-root-MuiSelect-root" + data-testid="test-version-select" > - <span + <div + aria-expanded="false" + aria-haspopup="listbox" + aria-label="Stats Test Version" + aria-labelledby="test-version-type mui-component-select-test_version" + class="MuiSelect-select MuiSelect-outlined MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall css-1rcoerw-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiOutlinedInput-input" + id="mui-component-select-test_version" + role="combobox" + tabindex="0" + > + Mann-Whitney-U + </div> + <input + aria-hidden="true" + aria-invalid="false" + class="MuiSelect-nativeInput css-j0riat-MuiSelect-nativeInput" + name="test_version" + tabindex="-1" + value="mann-whitney-u" + /> + <svg aria-hidden="true" - class="notranslate" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium MuiSelect-icon MuiSelect-iconOutlined css-h42w4p-MuiSvgIcon-root-MuiNativeSelect-root-MuiSelect-icon" + data-testid="ArrowDropDownIcon" + focusable="false" + viewBox="0 0 24 24" > - ​ - </span> - </legend> - </fieldset> + <path + d="M7 10l5 5 5-5z" + /> + </svg> + <fieldset + aria-hidden="true" + class="MuiOutlinedInput-notchedOutline css-18p5xg2-MuiNotchedOutlined-root-MuiOutlinedInput-notchedOutline" + > + <legend + class="css-1nf2c5d-MuiNotchedOutlined-root" + > + <span + aria-hidden="true" + class="notranslate" + > + ​ + </span> + </legend> + </fieldset> + </div> + </div> </div> - </div> - </div> - <div - class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-md-2 MuiGrid-grid-xs-6 css-4yvdwt-MuiGrid-root" - > - <div - class="MuiFormControl-root css-7549ua-MuiFormControl-root" - > <div - class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-formControl MuiInputBase-sizeSmall test-version-select MuiSelect-root css-fcr66i-MuiInputBase-root-MuiOutlinedInput-root-MuiSelect-root" - data-testid="test-version-select" + class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-grow css-vvfr7q-MuiGrid-root" > <div - aria-expanded="false" - aria-haspopup="listbox" - aria-label="Stats Test Version" - aria-labelledby="test-version-type mui-component-select-test_version" - class="MuiSelect-select MuiSelect-outlined MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall css-1hw1663-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiOutlinedInput-input" - id="mui-component-select-test_version" - role="combobox" - tabindex="0" + class="MuiBox-root css-0" + data-testid="revision-select" > - Mann-Whitney-U - </div> - <input - aria-hidden="true" - aria-invalid="false" - class="MuiSelect-nativeInput css-j0riat-MuiSelect-nativeInput" - name="test_version" - tabindex="-1" - value="mann-whitney-u" - /> - <svg - aria-hidden="true" - class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium MuiSelect-icon MuiSelect-iconOutlined css-h42w4p-MuiSvgIcon-root-MuiNativeSelect-root-MuiSelect-icon" - data-testid="ArrowDropDownIcon" - focusable="false" - viewBox="0 0 24 24" - > - <path - d="M7 10l5 5 5-5z" - /> - </svg> - <fieldset - aria-hidden="true" - class="MuiOutlinedInput-notchedOutline css-18p5xg2-MuiNotchedOutlined-root-MuiOutlinedInput-notchedOutline" - > - <legend - class="css-1nf2c5d-MuiNotchedOutlined-root" + <div + class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-sizeSmall f96or0t MuiSelect-root css-fcr66i-MuiInputBase-root-MuiOutlinedInput-root-MuiSelect-root" > - <span + <div + aria-expanded="false" + aria-haspopup="listbox" + aria-label="Filter by revision" + class="MuiSelect-select MuiSelect-outlined MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall css-1rcoerw-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiOutlinedInput-input" + role="combobox" + tabindex="0" + > + <div + class="fbc330 MuiBox-root css-0" + > + <svg + aria-hidden="true" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-120he73-MuiSvgIcon-root" + focusable="false" + viewBox="0 0 24 24" + > + <svg + aria-hidden="true" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-120he73-MuiSvgIcon-root" + data-testid="SortIcon" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M3 18h6v-2H3zM3 6v2h18V6zm0 7h12v-2H3z" + /> + </svg> + </svg> + All revisions + </div> + </div> + <input + aria-hidden="true" + aria-invalid="false" + class="MuiSelect-nativeInput css-j0riat-MuiSelect-nativeInput" + tabindex="-1" + value="all-revisions" + /> + <svg aria-hidden="true" - class="notranslate" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium MuiSelect-icon MuiSelect-iconOutlined css-h42w4p-MuiSvgIcon-root-MuiNativeSelect-root-MuiSelect-icon" + data-testid="ArrowDropDownIcon" + focusable="false" + viewBox="0 0 24 24" > - ​ - </span> - </legend> - </fieldset> + <path + d="M7 10l5 5 5-5z" + /> + </svg> + <fieldset + aria-hidden="true" + class="MuiOutlinedInput-notchedOutline css-18p5xg2-MuiNotchedOutlined-root-MuiOutlinedInput-notchedOutline" + > + <legend + class="css-1nf2c5d-MuiNotchedOutlined-root" + > + <span + aria-hidden="true" + class="notranslate" + > + ​ + </span> + </legend> + </fieldset> + </div> + </div> </div> - </div> - </div> - <div - class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-grow css-t3of1j-MuiGrid-root" - > - <div - class="MuiBox-root css-0" - data-testid="revision-select" - > <div - class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-sizeSmall f96or0t MuiSelect-root css-fcr66i-MuiInputBase-root-MuiOutlinedInput-root-MuiSelect-root" + class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-auto css-zh2j38-MuiGrid-root" > <div - aria-expanded="false" - aria-haspopup="listbox" - aria-label="Filter by revision" - class="MuiSelect-select MuiSelect-outlined MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall css-1hw1663-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiOutlinedInput-input" - role="combobox" - tabindex="0" + class="MuiFormControl-root css-1pn2fn8-MuiFormControl-root" > <div - class="fbc330 MuiBox-root css-0" + class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-formControl MuiInputBase-sizeSmall advanced-options-select MuiSelect-root css-fcr66i-MuiInputBase-root-MuiOutlinedInput-root-MuiSelect-root" + data-testid="advanced-options-select" > + <div + aria-expanded="false" + aria-haspopup="listbox" + aria-label="Advanced options" + class="MuiSelect-select MuiSelect-outlined MuiSelect-multiple MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall css-1rcoerw-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiOutlinedInput-input" + role="combobox" + tabindex="0" + > + Advanced options + </div> + <input + aria-hidden="true" + aria-invalid="false" + class="MuiSelect-nativeInput css-j0riat-MuiSelect-nativeInput" + tabindex="-1" + value="" + /> <svg aria-hidden="true" - class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-120he73-MuiSvgIcon-root" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium MuiSelect-icon MuiSelect-iconOutlined css-h42w4p-MuiSvgIcon-root-MuiNativeSelect-root-MuiSelect-icon" + data-testid="ArrowDropDownIcon" focusable="false" viewBox="0 0 24 24" > - <svg - aria-hidden="true" - class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-120he73-MuiSvgIcon-root" - data-testid="SortIcon" - focusable="false" - viewBox="0 0 24 24" - > - <path - d="M3 18h6v-2H3zM3 6v2h18V6zm0 7h12v-2H3z" - /> - </svg> + <path + d="M7 10l5 5 5-5z" + /> </svg> - All revisions + <fieldset + aria-hidden="true" + class="MuiOutlinedInput-notchedOutline css-18p5xg2-MuiNotchedOutlined-root-MuiOutlinedInput-notchedOutline" + > + <legend + class="css-1nf2c5d-MuiNotchedOutlined-root" + > + <span + aria-hidden="true" + class="notranslate" + > + ​ + </span> + </legend> + </fieldset> </div> </div> - <input - aria-hidden="true" - aria-invalid="false" - class="MuiSelect-nativeInput css-j0riat-MuiSelect-nativeInput" - tabindex="-1" - value="all-revisions" - /> - <svg - aria-hidden="true" - class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium MuiSelect-icon MuiSelect-iconOutlined css-h42w4p-MuiSvgIcon-root-MuiNativeSelect-root-MuiSelect-icon" - data-testid="ArrowDropDownIcon" - focusable="false" - viewBox="0 0 24 24" - > - <path - d="M7 10l5 5 5-5z" - /> - </svg> - <fieldset - aria-hidden="true" - class="MuiOutlinedInput-notchedOutline css-18p5xg2-MuiNotchedOutlined-root-MuiOutlinedInput-notchedOutline" + </div> + <div + class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-grow css-wautn6-MuiGrid-root" + > + <div + class="f6hg2jo" > - <legend - class="css-1nf2c5d-MuiNotchedOutlined-root" + <button + class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedSecondary MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButton-colorSecondary MuiButton-disableElevation css-14hwkrj-MuiButtonBase-root-MuiButton-root" + tabindex="0" + type="button" > - <span - aria-hidden="true" - class="notranslate" - > - ​ - </span> - </legend> - </fieldset> + Download JSON + </button> + </div> </div> </div> </div> - <div - class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-grow css-t3of1j-MuiGrid-root" - > - <div - class="f6hg2jo" - > - <button - class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedSecondary MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButton-colorSecondary MuiButton-disableElevation css-14hwkrj-MuiButtonBase-root-MuiButton-root" - tabindex="0" - type="button" - > - Download JSON - </button> - </div> - </div> - <div - class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-auto css-zh2j38-MuiGrid-root" - > - <label - aria-label="Expand all rows" - class="MuiFormControlLabel-root MuiFormControlLabel-labelPlacementEnd css-1bsjtco-MuiFormControlLabel-root" - data-mui-internal-clone-element="true" - > - <span - class="MuiButtonBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall PrivateSwitchBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall css-1nff2up-MuiButtonBase-root-MuiSwitchBase-root-MuiCheckbox-root" - > - <input - class="PrivateSwitchBase-input css-12xagqm-MuiSwitchBase-root" - data-indeterminate="false" - type="checkbox" - /> - <svg - aria-hidden="true" - class="MuiSvgIcon-root MuiSvgIcon-fontSizeSmall css-54rgmy-MuiSvgIcon-root" - data-testid="CheckBoxOutlineBlankIcon" - focusable="false" - viewBox="0 0 24 24" - > - <path - d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z" - /> - </svg> - </span> - <span - class="MuiTypography-root MuiTypography-body1 MuiFormControlLabel-label css-n290n7-MuiTypography-root" - > - Expand all - </span> - </label> - </div> </div> <div - class="fdtnfac f1l733lh" + class="flb4c18 f1l733lh table-header" data-testid="table-header" role="row" > @@ -357,7 +455,7 @@ exports[`Results View The table should match snapshot and other elements should <button aria-haspopup="true" aria-label="Platform (Click to filter values)" - class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedTableHeaderButton MuiButton-sizeSmall MuiButton-containedSizeSmall MuiButton-colorTableHeaderButton MuiButton-disableElevation css-l81dbu-MuiButtonBase-root-MuiButton-root" + class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedTableHeaderButton MuiButton-sizeSmall MuiButton-containedSizeSmall MuiButton-colorTableHeaderButton MuiButton-disableElevation css-kne8o5-MuiButtonBase-root-MuiButton-root" data-mui-internal-clone-element="true" tabindex="0" type="button" @@ -417,13 +515,13 @@ exports[`Results View The table should match snapshot and other elements should role="columnheader" > <span - aria-label="Median Diff %: The percentage change in median from Base to New: ((New − Base) / Base) × 100." + aria-label="Shows how much the middle result changed from Base to New. We line up all the runs from smallest to biggest and pick the middle one for each side, then show the change as a percent. A positive sign means New is higher; a negative sign means New is lower." class="MuiBox-root css-1tkq7a4" data-mui-internal-clone-element="true" > <button - aria-label="MD (%) (Click to sort by this column)" - class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedTableHeaderButton MuiButton-sizeSmall MuiButton-containedSizeSmall MuiButton-colorTableHeaderButton MuiButton-disableElevation css-7upxw3-MuiButtonBase-root-MuiButton-root" + aria-label="Δ Median (Click to sort by this column)" + class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedTableHeaderButton MuiButton-sizeSmall MuiButton-containedSizeSmall MuiButton-colorTableHeaderButton MuiButton-disableElevation css-1w0uvhi-MuiButtonBase-root-MuiButton-root" tabindex="0" type="button" > @@ -438,10 +536,10 @@ exports[`Results View The table should match snapshot and other elements should d="M16 17.01V10h-2v7.01h-3L15 21l4-3.99zM9 3 5 6.99h3V14h2V6.99h3z" /> <title> - Not sorted by MD (%) + Not sorted by Δ Median - MD (%) + Δ Median @@ -452,18 +550,18 @@ exports[`Results View The table should match snapshot and other elements should - - -
- - - -
-
- 0 % + +1.08%
-
-
- - -
-
- - + class="MuiBox-root css-izuqqr" + > +
+
- @@ -1116,7 +1134,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- 0 % + -2.40%
-
-
- - -
-
- - + class="MuiBox-root css-izuqqr" + > +
+
- @@ -1315,7 +1325,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- 0 % + -2.40%
-
-
- - -
-
- - + class="MuiBox-root css-izuqqr" + > +
+
- @@ -1514,7 +1516,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
@@ -264,7 +264,7 @@ exports[`Results Table Should match snapshot 1`] = ` aria-expanded="false" aria-haspopup="listbox" aria-labelledby="repo-dropdown--base" - class="MuiSelect-select MuiSelect-standard MuiInputBase-input MuiInput-input MuiInputBase-inputSizeSmall css-10dumzv-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiInput-input" + class="MuiSelect-select MuiSelect-standard MuiInputBase-input MuiInput-input MuiInputBase-inputSizeSmall css-1bf5zjw-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiInput-input" role="combobox" tabindex="0" > @@ -591,7 +591,7 @@ exports[`Results Table Should match snapshot 1`] = ` aria-expanded="false" aria-haspopup="listbox" aria-labelledby="repo-dropdown--new" - class="MuiSelect-select MuiSelect-standard MuiInputBase-input MuiInput-input MuiInputBase-inputSizeSmall css-10dumzv-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiInput-input" + class="MuiSelect-select MuiSelect-standard MuiInputBase-input MuiInput-input MuiInputBase-inputSizeSmall css-1bf5zjw-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiInput-input" role="combobox" tabindex="0" > @@ -894,7 +894,7 @@ exports[`Results Table Should match snapshot 1`] = ` class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-12 css-16nz7cf-MuiGrid-root" >
@@ -971,9 +971,159 @@ exports[`Results Table Should match snapshot 1`] = ` The performance comparison shown here may not reflect what performance alerts are generated in CI. Conversely, a performance comparison from a generated alert in CI may not reflect the changes shown here. For a comparison that currently reflects our CI detection system, select the Student-T Test option.
+
+ +
+
-
-
+ + + + + + How to read the results + + + +
+
+
+
+
+ +
+
+
+ + +
+ +
+ +
+ +
+
+ +
+
- + talos +
+ -
- -
- + + +
-
- -
-
-
- - -
+ + + +
+
-
-
-
-
- - -
+ + + +
+
-
-
-
-
- - - + Download JSON + +
-
-
- -
-
-
- -
@@ -1330,7 +1578,7 @@ exports[`Results Table Should match snapshot 1`] = `
@@ -1425,18 +1673,18 @@ exports[`Results Table Should match snapshot 1`] = ` - - -
- - - -
-
- 0 % + +1.08%
-
-
- - -
-
- - + class="MuiBox-root css-izuqqr" + > +
+
- @@ -2089,7 +2257,7 @@ exports[`Results Table Should match snapshot 1`] = ` data-testid="expand-revision-button" >
- 0 % + -2.40%
-
-
- - -
-
- - + class="MuiBox-root css-izuqqr" + > +
+
- @@ -2288,7 +2448,7 @@ exports[`Results Table Should match snapshot 1`] = ` data-testid="expand-revision-button" >
@@ -3147,7 +3299,7 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion aria-expanded="false" aria-haspopup="listbox" aria-labelledby="repo-dropdown--base" - class="MuiSelect-select MuiSelect-standard MuiInputBase-input MuiInput-input MuiInputBase-inputSizeSmall css-10dumzv-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiInput-input" + class="MuiSelect-select MuiSelect-standard MuiInputBase-input MuiInput-input MuiInputBase-inputSizeSmall css-1bf5zjw-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiInput-input" role="combobox" tabindex="0" > @@ -3224,7 +3376,7 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion autocapitalize="none" autocomplete="off" class="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall MuiInputBase-inputAdornedStart MuiInputBase-inputAdornedEnd MuiAutocomplete-input MuiAutocomplete-inputFocused css-16cokj7-MuiInputBase-input-MuiOutlinedInput-input" - id="_r_qb_" + id="_r_qp_" placeholder="Search by revision ID or author email" role="combobox" spellcheck="false" @@ -3474,7 +3626,7 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion aria-expanded="false" aria-haspopup="listbox" aria-labelledby="repo-dropdown--new" - class="MuiSelect-select MuiSelect-standard MuiInputBase-input MuiInput-input MuiInputBase-inputSizeSmall css-10dumzv-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiInput-input" + class="MuiSelect-select MuiSelect-standard MuiInputBase-input MuiInput-input MuiInputBase-inputSizeSmall css-1bf5zjw-MuiNativeSelect-root-MuiSelect-select-MuiInputBase-input-MuiInput-input" role="combobox" tabindex="0" > @@ -3551,7 +3703,7 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion autocapitalize="none" autocomplete="off" class="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall MuiInputBase-inputAdornedStart MuiInputBase-inputAdornedEnd MuiAutocomplete-input MuiAutocomplete-inputFocused css-16cokj7-MuiInputBase-input-MuiOutlinedInput-input" - id="_r_qj_" + id="_r_r1_" placeholder="Search by revision ID or author email" role="combobox" spellcheck="false" @@ -3777,7 +3929,7 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-12 css-16nz7cf-MuiGrid-root" >
@@ -3854,9 +4006,159 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion The performance comparison shown here may not reflect what performance alerts are generated in CI. Conversely, a performance comparison from a generated alert in CI may not reflect the changes shown here. For a comparison that currently reflects our CI detection system, select the Student-T Test option.
+
+ +
+
+
+ + +
+
+
-
+ +
+
+
+ + +
+ +
+ +
+ +
+
+ +
+
- + talos +
+ -
- -
- + + +
-
- -
-
-
- - -
+ +
-
-
-
-
-
- - - - +
+
-
-
-
-
- - - + + + +
+
-
- -
-
- -
-
-
- + +
+ +
@@ -4213,7 +4613,7 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion
@@ -4308,18 +4708,18 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion @@ -4409,7 +4809,7 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion > + + + + + + +
- + build_metrics +
+ -
- -
- + + +
-
- - -
-
- - -
+ +
-
- -
-
+ + + +
+
+
- - -
+ + + + + - - -
-
- - - + Download JSON + +
-
-
- -
-
-
- -
@@ -1512,7 +874,7 @@ exports[`Results View The table should match snapshot and other elements should
@@ -1607,18 +969,18 @@ exports[`Results View The table should match snapshot and other elements should - - -
- - - -
-
- 0 % + +1.08%
-
-
- - -
-
- - + class="MuiBox-root css-izuqqr" + > +
+
- @@ -2271,7 +1553,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- 0 % + -2.40%
-
-
- - -
-
- - + class="MuiBox-root css-izuqqr" + > +
+
- @@ -2470,7 +1744,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- 0 % + -2.40%
-
-
- - -
-
- - + class="MuiBox-root css-izuqqr" + > +
+
- @@ -2669,7 +1935,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
@@ -494,7 +494,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-12 css-16nz7cf-MuiGrid-root" >
@@ -602,6 +602,32 @@ exports[`SubtestsResultsView Component Tests should render the subtests results report it on Bugzilla . + + The performance comparison shown here may not reflect what performance alerts are generated in CI. Conversely, a performance comparison from a generated alert in CI may not reflect the changes shown here. For a comparison that currently reflects our CI detection system, select the Student-T Test option. + +
+
+
+
+
+
+ + + + +
+
+
@@ -850,7 +932,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results >
@@ -939,18 +1021,18 @@ exports[`SubtestsResultsView Component Tests should render the subtests results
- - - -
-
- - - -
-
- 0 % + +1.14%
-
-
- - - -
-
- 0.00% + class="MuiBox-root css-izuqqr" + > +
+
- @@ -1252,7 +1261,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
- 0 % + +1.14%
-
-
- - - -
-
- 0.00% + class="MuiBox-root css-izuqqr" + > +
+
- @@ -1400,7 +1400,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
- 0 % + +1.14%
-
-
- - - -
-
- 0.00% + class="MuiBox-root css-izuqqr" + > +
+
- @@ -1548,7 +1539,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
- 0 % + +1.14%
-
-
- - - -
-
- 0.00% + class="MuiBox-root css-izuqqr" + > +
+
- @@ -1696,7 +1678,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
- 0 % + +0.98%
-
-
- - - -
-
- 0.00% + class="MuiBox-root css-izuqqr" + > +
+
- @@ -1844,7 +1817,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
@@ -2413,7 +2386,7 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-12 css-16nz7cf-MuiGrid-root" >
@@ -2521,6 +2494,32 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi report it on Bugzilla . + + The performance comparison shown here may not reflect what performance alerts are generated in CI. Conversely, a performance comparison from a generated alert in CI may not reflect the changes shown here. For a comparison that currently reflects our CI detection system, select the Student-T Test option. + +
+
+
+
+
+
+ + + + +
+
+
@@ -2761,7 +2816,7 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi >
@@ -2850,18 +2905,18 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi
- - -
-
- - - -
-
-
-
- 0.963 % + +1.14%
-
-
- - -0.04 -
-
- 15.00% + class="MuiBox-root css-izuqqr" + > +
+ Noise +
+
+
- - + Negligible
- 1.135 % + +1.14%
- - Regression + + Regression +
- - 0.02 -
-
- 60.00% -
-
- + Negligible
- 0.963 % + +1.14%
-
-
- - -0.05 + class="MuiBox-root css-izuqqr" + > +
+
- 50.00% -
-
- + Negligible
- 1.135 % + +1.14%
-
-
- - 0.12 -
-
- 25.00% + class="MuiBox-root css-izuqqr" + > +
+
- + Small
- 0.98 % + +0.98%
- - Improvement + + Improvement +
- - 0.01 -
-
- 45.00% -
-
- - + Negligible
@@ -4015,7 +3927,7 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-12 css-16nz7cf-MuiGrid-root" >
@@ -4123,6 +4035,32 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi report it on Bugzilla . + + The performance comparison shown here may not reflect what performance alerts are generated in CI. Conversely, a performance comparison from a generated alert in CI may not reflect the changes shown here. For a comparison that currently reflects our CI detection system, select the Student-T Test option. + +
+
+
+
+
+
+ + + + +
+
+
@@ -4363,7 +4357,7 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi >
@@ -4452,18 +4446,18 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi
- - - -
-
- - - -
-
- 0.963 % + +1.14%
-
-
- - -0.04 -
-
- 15.00% + class="MuiBox-root css-izuqqr" + > +
+ Noise +
+
+
- - + Negligible
- 1.135 % + +1.14%
- - Regression + + Regression +
- - 0.02 -
-
- 60.00% -
-
- + > + Negligible
- 0.963 % + +1.14%
-
-
- - -0.05 -
-
- 50.00% + class="MuiBox-root css-izuqqr" + > +
+
- + Negligible
- 1.135 % + +1.14%
-
-
- - 0.12 -
-
- 25.00% + class="MuiBox-root css-izuqqr" + > +
+
- + Small
- 0.98 % + +0.98%
- - Improvement + + Improvement +
- - 0.01 -
-
- 45.00% -
-
- - + Negligible
@@ -5617,7 +5468,7 @@ exports[`SubtestsViewCompareOverTime Component Tests renders over-time view when class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-12 css-16nz7cf-MuiGrid-root" >
@@ -5725,6 +5576,32 @@ exports[`SubtestsViewCompareOverTime Component Tests renders over-time view when report it on Bugzilla . + + The performance comparison shown here may not reflect what performance alerts are generated in CI. Conversely, a performance comparison from a generated alert in CI may not reflect the changes shown here. For a comparison that currently reflects our CI detection system, select the Student-T Test option. + +
+
+
+
+
+
+ + + + +
+
+
@@ -5965,7 +5898,7 @@ exports[`SubtestsViewCompareOverTime Component Tests renders over-time view when >
@@ -6054,18 +5987,18 @@ exports[`SubtestsViewCompareOverTime Component Tests renders over-time view when
- - - -
-
- - - -
-
- 0.963 % + +1.14%
-
-
- - -0.04 -
-
- 15.00% + class="MuiBox-root css-izuqqr" + > +
+ Noise +
+
+
- - + Negligible
- 1.135 % + +1.14%
- - Regression + + Regression +
- - 0.02 -
-
- 60.00% -
-
- + Negligible
- - 0.963 % - -
-
-
-
-
- - -0.05 -
-
- 50.00% + + +1.14% +
- +
+
+
+ Negligible
- 1.135 % + +1.14%
-
-
- - 0.12 -
-
- 25.00% + class="MuiBox-root css-izuqqr" + > +
+
- + Small
- 0.98 % + +0.98%
- - Improvement + + Improvement +
- - 0.01 -
-
- 45.00% -
-
- - + Negligible
@@ -7219,7 +7009,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-12 css-16nz7cf-MuiGrid-root" >
@@ -7327,6 +7117,32 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests report it on Bugzilla . + + The performance comparison shown here may not reflect what performance alerts are generated in CI. Conversely, a performance comparison from a generated alert in CI may not reflect the changes shown here. For a comparison that currently reflects our CI detection system, select the Student-T Test option. + +
+
+
+
+
+
+ + + + +
+
+
@@ -7567,7 +7439,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests >
@@ -7656,18 +7528,18 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests
- - - -
-
- - - -
-
- 0 % + +1.14%
-
-
- - - -
-
- 0.00% + class="MuiBox-root css-izuqqr" + > +
+
- @@ -7969,7 +7768,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
- 0 % + +1.14%
-
-
- - - -
-
- 0.00% + class="MuiBox-root css-izuqqr" + > +
+
- @@ -8117,7 +7907,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
- 0 % + +1.14%
-
-
- - - -
-
- 0.00% + class="MuiBox-root css-izuqqr" + > +
+
- @@ -8265,7 +8046,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
- 0 % + +1.14%
-
-
- - - -
-
- 0.00% + class="MuiBox-root css-izuqqr" + > +
+
- @@ -8413,7 +8185,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
- 0 % + +0.98%
-
-
- - - -
-
- 0.00% + class="MuiBox-root css-izuqqr" + > +
+
- @@ -8561,7 +8324,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >