diff --git a/jest.bench.config.js b/jest.bench.config.js index 8a39b14d..880f918d 100644 --- a/jest.bench.config.js +++ b/jest.bench.config.js @@ -1,16 +1,13 @@ export default { - // Jest-bench need its own test environment to function - testEnvironment: "jest-bench/environment", - testEnvironmentOptions: { - // still Jest-bench environment will run your environment if you specify it here - testEnvironment: "jest-environment-node", - testEnvironmentOptions: { - // specify any option for your environment - }, - }, - // always include "default" reporter along with Jest-bench reporter - // for error reporting - reporters: ["default", "jest-bench/reporter"], - // will pick up "*.bench.js" file. + clearMocks: true, + transform: {}, + testEnvironment: "jsdom", + coverageProvider: "v8", + testPathIgnorePatterns: ["/node_modules/", "/tests/e2e/"], + modulePathIgnorePatterns: ["/node_modules/", "/tests/e2e/"], + coveragePathIgnorePatterns: [ + "/node_modules/", + "/tests/e2e/", + ], testRegex: "(\\.bench)\\.(ts|tsx|js)$", }; diff --git a/package-lock.json b/package-lock.json index 01cdd0e3..7306b2b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,6 @@ "hjson": "^3.2.2", "husky": "^9.1.7", "jest": "^29.7.0", - "jest-bench": "^29.7.1", "jest-environment-jsdom": "^30.1.2", "js-yaml": "^4.1.0", "lint-staged": "^16.2.0", @@ -2349,16 +2348,6 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/benchmark": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", - "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", - "dev": true, - "dependencies": { - "lodash": "^4.17.4", - "platform": "^1.3.3" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3165,18 +3154,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/@eslint/js": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", - "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -4176,23 +4153,6 @@ } } }, - "node_modules/jest-bench": { - "version": "29.7.1", - "resolved": "https://registry.npmjs.org/jest-bench/-/jest-bench-29.7.1.tgz", - "integrity": "sha512-eFjQa+KVThwqY+Ecs9jeD+CdTUlDrJUAAFLy+DlWW5H1crnG1F4ad5Dk8K+kV6nB2aGCdFcusKBdgtx1SXYiHQ==", - "dev": true, - "dependencies": { - "@jest/globals": "^29.7.0", - "@jest/reporters": "^29.7.0", - "benchmark": "^2.1.4", - "chalk": "^4.1.0", - "lodash": "^4.17.20", - "ndjson": "^2.0.0" - }, - "peerDependencies": { - "jest": "^29.7.0" - } - }, "node_modules/jest-changed-files": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", @@ -5356,12 +5316,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -5539,12 +5493,6 @@ "node": ">=8" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5833,15 +5781,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5866,25 +5805,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/ndjson": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-2.0.0.tgz", - "integrity": "sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==", - "dev": true, - "dependencies": { - "json-stringify-safe": "^5.0.1", - "minimist": "^1.2.5", - "readable-stream": "^3.6.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - }, - "bin": { - "ndjson": "cli.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -6169,12 +6089,6 @@ "node": ">=8" } }, - "node_modules/platform": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", - "dev": true - }, "node_modules/prettier": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", @@ -6265,20 +6179,6 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -6409,26 +6309,6 @@ "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", "dev": true }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -6582,15 +6462,6 @@ "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", "dev": true }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "dependencies": { - "readable-stream": "^3.0.0" - } - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -6609,15 +6480,6 @@ "node": ">=10" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-argv": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", @@ -6752,15 +6614,6 @@ "node": ">=8" } }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "dependencies": { - "readable-stream": "3" - } - }, "node_modules/tldts": { "version": "6.1.86", "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", @@ -6924,12 +6777,6 @@ "punycode": "^2.1.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, "node_modules/v8-to-istanbul": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", @@ -8927,16 +8774,6 @@ "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", "dev": true }, - "benchmark": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", - "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", - "dev": true, - "requires": { - "lodash": "^4.17.4", - "platform": "^1.3.3" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -9430,12 +9267,6 @@ "optionator": "^0.9.3" }, "dependencies": { - "@eslint/js": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", - "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", - "dev": true - }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -10172,20 +10003,6 @@ "jest-cli": "^29.7.0" } }, - "jest-bench": { - "version": "29.7.1", - "resolved": "https://registry.npmjs.org/jest-bench/-/jest-bench-29.7.1.tgz", - "integrity": "sha512-eFjQa+KVThwqY+Ecs9jeD+CdTUlDrJUAAFLy+DlWW5H1crnG1F4ad5Dk8K+kV6nB2aGCdFcusKBdgtx1SXYiHQ==", - "dev": true, - "requires": { - "@jest/globals": "^29.7.0", - "@jest/reporters": "^29.7.0", - "benchmark": "^2.1.4", - "chalk": "^4.1.0", - "lodash": "^4.17.20", - "ndjson": "^2.0.0" - } - }, "jest-changed-files": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", @@ -11083,12 +10900,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -11211,12 +11022,6 @@ "p-locate": "^4.1.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -11422,12 +11227,6 @@ "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true - }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -11446,19 +11245,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "ndjson": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-2.0.0.tgz", - "integrity": "sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==", - "dev": true, - "requires": { - "json-stringify-safe": "^5.0.1", - "minimist": "^1.2.5", - "readable-stream": "^3.6.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - } - }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -11670,12 +11456,6 @@ "find-up": "^4.0.0" } }, - "platform": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", - "dev": true - }, "prettier": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", @@ -11734,17 +11514,6 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, "redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -11838,12 +11607,6 @@ "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", "dev": true }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -11963,15 +11726,6 @@ "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", "dev": true }, - "split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "requires": { - "readable-stream": "^3.0.0" - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -11987,15 +11741,6 @@ "escape-string-regexp": "^2.0.0" } }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, "string-argv": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", @@ -12091,15 +11836,6 @@ "minimatch": "^3.0.4" } }, - "through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "requires": { - "readable-stream": "3" - } - }, "tldts": { "version": "6.1.86", "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", @@ -12211,12 +11947,6 @@ "punycode": "^2.1.0" } }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, "v8-to-istanbul": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", diff --git a/package.json b/package.json index cdbdebd3..00375951 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,6 @@ "hjson": "^3.2.2", "husky": "^9.1.7", "jest": "^29.7.0", - "jest-bench": "^29.7.1", "jest-environment-jsdom": "^30.1.2", "js-yaml": "^4.1.0", "lint-staged": "^16.2.0", diff --git a/tests/bench/api.bench.js b/tests/bench/api.bench.js index f5f192d9..d6581da3 100644 --- a/tests/bench/api.bench.js +++ b/tests/bench/api.bench.js @@ -1,8 +1,8 @@ -import { benchmarkSuite } from "jest-bench"; import api from "../../api/index.js"; import axios from "axios"; import MockAdapter from "axios-mock-adapter"; -import { jest } from "@jest/globals"; +import { it, jest } from "@jest/globals"; +import { runAndLogStats } from "./utils.js"; const stats = { name: "Anurag Hazra", @@ -69,10 +69,10 @@ const faker = (query, data) => { return { req, res }; }; -benchmarkSuite("test /api", { - ["simple request"]: async () => { +it("test /api", async () => { + await runAndLogStats("test /api", async () => { const { req, res } = faker({}, data_stats); await api(req, res); - }, + }); }); diff --git a/tests/bench/calculateRank.bench.js b/tests/bench/calculateRank.bench.js index 1ce6b05b..6907dd21 100644 --- a/tests/bench/calculateRank.bench.js +++ b/tests/bench/calculateRank.bench.js @@ -1,8 +1,9 @@ -import { benchmarkSuite } from "jest-bench"; import { calculateRank } from "../../src/calculateRank.js"; +import { it } from "@jest/globals"; +import { runAndLogStats } from "./utils.js"; -benchmarkSuite("calculateRank", { - ["calculateRank"]: () => { +it("calculateRank", async () => { + await runAndLogStats("calculateRank", () => { calculateRank({ all_commits: false, commits: 1300, @@ -13,5 +14,5 @@ benchmarkSuite("calculateRank", { stars: 600000, followers: 50000, }); - }, + }); }); diff --git a/tests/bench/gist.bench.js b/tests/bench/gist.bench.js index 69f38137..66e618ec 100644 --- a/tests/bench/gist.bench.js +++ b/tests/bench/gist.bench.js @@ -1,8 +1,8 @@ -import { benchmarkSuite } from "jest-bench"; import gist from "../../api/gist.js"; import axios from "axios"; import MockAdapter from "axios-mock-adapter"; -import { jest } from "@jest/globals"; +import { it, jest } from "@jest/globals"; +import { runAndLogStats } from "./utils.js"; const gist_data = { data: { @@ -34,8 +34,8 @@ const gist_data = { const mock = new MockAdapter(axios); mock.onPost("https://api.github.com/graphql").reply(200, gist_data); -benchmarkSuite("test /api/gist", { - ["simple request"]: async () => { +it("test /api/gist", async () => { + await runAndLogStats("test /api/gist", async () => { const req = { query: { id: "bbfce31e0217a3689c8d961a356cb10d", @@ -47,5 +47,5 @@ benchmarkSuite("test /api/gist", { }; await gist(req, res); - }, + }); }); diff --git a/tests/bench/pin.bench.js b/tests/bench/pin.bench.js index 636e0d58..9a249846 100644 --- a/tests/bench/pin.bench.js +++ b/tests/bench/pin.bench.js @@ -1,8 +1,8 @@ -import { benchmarkSuite } from "jest-bench"; import pin from "../../api/pin.js"; import axios from "axios"; import MockAdapter from "axios-mock-adapter"; -import { jest } from "@jest/globals"; +import { it, jest } from "@jest/globals"; +import { runAndLogStats } from "./utils.js"; const data_repo = { repository: { @@ -32,8 +32,8 @@ const data_user = { const mock = new MockAdapter(axios); mock.onPost("https://api.github.com/graphql").reply(200, data_user); -benchmarkSuite("test /api/pin", { - ["simple request"]: async () => { +it("test /api/pin", async () => { + await runAndLogStats("test /api/pin", async () => { const req = { query: { username: "anuraghazra", @@ -46,5 +46,5 @@ benchmarkSuite("test /api/pin", { }; await pin(req, res); - }, + }); }); diff --git a/tests/bench/utils.js b/tests/bench/utils.js new file mode 100644 index 00000000..a94b258b --- /dev/null +++ b/tests/bench/utils.js @@ -0,0 +1,127 @@ +const DEFAULT_RUNS = 1000; +const DEFAULT_WARMUPS = 50; + +/** + * Formats a duration in nanoseconds to a compact human-readable string. + * @param {bigint} ns Duration in nanoseconds. + * @returns {string} Formatted time string. + */ +const formatTime = (ns) => { + if (ns < 1_000n) { + return `${ns}ns`; + } + if (ns < 1_000_000n) { + return `${Number(ns) / 1_000}µs`; + } + if (ns < 1_000_000_000n) { + return `${(Number(ns) / 1_000_000).toFixed(3)}ms`; + } + return `${(Number(ns) / 1_000_000_000).toFixed(3)}s`; +}; + +/** + * Measures synchronous or async function execution time. + * @param {Function} fn Function to measure. + * @returns {Promise} elapsed nanoseconds + */ +const measurePerformance = async (fn) => { + const start = process.hrtime.bigint(); + const ret = fn(); + if (ret instanceof Promise) { + await ret; + } + const end = process.hrtime.bigint(); + return end - start; +}; + +/** + * Computes basic & extended statistics. + * @param {bigint[]} samples Array of samples in nanoseconds. + * @returns {object} Stats + */ +const computeStats = (samples) => { + const sorted = [...samples].sort((a, b) => (a < b ? -1 : 1)); + const toNumber = (b) => Number(b); // safe for typical short benches + const n = sorted.length; + const sum = sorted.reduce((a, b) => a + b, 0n); + const avg = Number(sum) / n; + const median = + n % 2 + ? toNumber(sorted[(n - 1) / 2]) + : (toNumber(sorted[n / 2 - 1]) + toNumber(sorted[n / 2])) / 2; + const p = (q) => { + const idx = Math.min(n - 1, Math.floor((q / 100) * n)); + return toNumber(sorted[idx]); + }; + const min = toNumber(sorted[0]); + const max = toNumber(sorted[n - 1]); + const variance = + sorted.reduce((acc, v) => acc + (toNumber(v) - avg) ** 2, 0) / n; + const stdev = Math.sqrt(variance); + + return { + runs: n, + min, + max, + average: avg, + median, + p75: p(75), + p95: p(95), + p99: p(99), + stdev, + totalTime: toNumber(sum), + }; +}; + +/** + * Benchmark a function. + * @param {string} fnName Name of the function (for logging). + * @param {Function} fn Function to benchmark. + * @param {object} [opts] Options. + * @param {number} [opts.runs] Number of measured runs. + * @param {number} [opts.warmup] Warm-up iterations (not measured). + * @param {boolean} [opts.trimOutliers] Drop top & bottom 1% before stats. + * @returns {Promise} Stats (nanoseconds for core metrics). + */ +export const runAndLogStats = async ( + fnName, + fn, + { runs = DEFAULT_RUNS, warmup = DEFAULT_WARMUPS, trimOutliers = false } = {}, +) => { + if (runs <= 0) { + throw new Error("Number of runs must be positive."); + } + + // Warm-up + for (let i = 0; i < warmup; i++) { + const ret = fn(); + if (ret instanceof Promise) { + await ret; + } + } + + const samples = []; + for (let i = 0; i < runs; i++) { + samples.push(await measurePerformance(fn)); + } + + let processed = samples; + if (trimOutliers && samples.length > 10) { + const sorted = [...samples].sort((a, b) => (a < b ? -1 : 1)); + const cut = Math.max(1, Math.floor(sorted.length * 0.01)); + processed = sorted.slice(cut, sorted.length - cut); + } + + const stats = computeStats(processed); + + const fmt = (ns) => formatTime(BigInt(Math.round(ns))); + console.log( + `${fnName} | runs=${stats.runs} avg=${fmt(stats.average)} median=${fmt( + stats.median, + )} p95=${fmt(stats.p95)} min=${fmt(stats.min)} max=${fmt( + stats.max, + )} stdev=${fmt(stats.stdev)}`, + ); + + return stats; +};