fix(ui): update fetch

This commit is contained in:
Lukasz Mierzwa
2026-02-23 12:44:36 +00:00
committed by Łukasz Mierzwa
parent 675e687dd7
commit dc5a640bb7
27 changed files with 618 additions and 610 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ ignores:
- "eslint-plugin-jest"
- "node-fetch"
- eslint
- fetch-mock
- identity-obj-proxy
- jest
- jest-fetch-mock
- terser
+133 -163
View File
@@ -52,6 +52,7 @@
"typeface-open-sans": "1.1.13"
},
"devDependencies": {
"@fetch-mock/jest": "0.2.20",
"@testing-library/jest-dom": "6.9.1",
"@testing-library/react": "12.1.5",
"@testing-library/react-hooks": "8.0.1",
@@ -80,12 +81,11 @@
"eslint-plugin-prettier": "5.5.5",
"eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "5.2.0",
"fetch-mock": "9.11.0",
"fetch-mock": "12.6.0",
"identity-obj-proxy": "3.0.0",
"jest": "30.2.0",
"jest-environment-jsdom": "30.2.0",
"jest-fetch-mock": "3.0.3",
"node-fetch": "2.7.0",
"node-fetch": "3.3.2",
"prettier": "3.8.1",
"sass": "1.97.3",
"terser": "5.46.0",
@@ -2769,6 +2769,23 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@fetch-mock/jest": {
"version": "0.2.20",
"resolved": "https://registry.npmjs.org/@fetch-mock/jest/-/jest-0.2.20.tgz",
"integrity": "sha512-DGX2bhBInodaWPMV3+UZ530aVM3wDj16sAPjFzkrwb0JwNWIQK07CNbYprQ3Tmd2ixDJeaNx2E0aNb+hRb8FFA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fetch-mock": "^12.6.0"
},
"engines": {
"node": ">=18.11.0"
},
"peerDependencies": {
"@jest/globals": "*",
"jest": "*"
}
},
"node_modules/@floating-ui/core": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz",
@@ -4578,6 +4595,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/glob-to-regexp": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/@types/glob-to-regexp/-/glob-to-regexp-0.4.4.tgz",
"integrity": "sha512-nDKoaKJYbnn1MZxUY0cA1bPmmgZbg0cTq7Rh13d0KWYNOiKbqoR+2d89SnRPszGh7ROzSwZ/GOjZ4jPbmmZ6Eg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
@@ -6338,16 +6362,6 @@
"node": ">= 6"
}
},
"node_modules/cross-fetch": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz",
"integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"node-fetch": "^2.7.0"
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -6395,6 +6409,16 @@
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"license": "MIT"
},
"node_modules/data-uri-to-buffer": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 12"
}
},
"node_modules/data-urls": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
@@ -7531,38 +7555,44 @@
"bser": "2.1.1"
}
},
"node_modules/fetch-blob": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "paypal",
"url": "https://paypal.me/jimmywarting"
}
],
"license": "MIT",
"dependencies": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
}
},
"node_modules/fetch-mock": {
"version": "9.11.0",
"resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-9.11.0.tgz",
"integrity": "sha512-PG1XUv+x7iag5p/iNHD4/jdpxL9FtVSqRMUQhPab4hVDt80T1MH5ehzVrL2IdXO9Q2iBggArFvPqjUbHFuI58Q==",
"version": "12.6.0",
"resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-12.6.0.tgz",
"integrity": "sha512-oAy0OqAvjAvduqCeWveBix7LLuDbARPqZZ8ERYtBcCURA3gy7EALA3XWq0tCNxsSg+RmmJqyaeeZlOCV9abv6w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.0.0",
"@babel/runtime": "^7.0.0",
"core-js": "^3.0.0",
"debug": "^4.1.1",
"glob-to-regexp": "^0.4.0",
"is-subset": "^0.1.1",
"lodash.isequal": "^4.5.0",
"path-to-regexp": "^2.2.1",
"querystring": "^0.2.0",
"whatwg-url": "^6.5.0"
"@types/glob-to-regexp": "^0.4.4",
"dequal": "^2.0.3",
"glob-to-regexp": "^0.4.1",
"regexparam": "^3.0.0"
},
"engines": {
"node": ">=4.0.0"
},
"funding": {
"type": "charity",
"url": "https://www.justgiving.com/refugee-support-europe"
},
"peerDependencies": {
"node-fetch": "*"
},
"peerDependenciesMeta": {
"node-fetch": {
"optional": true
}
"node": ">=18.11.0"
}
},
"node_modules/file-entry-cache": {
@@ -7670,6 +7700,19 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"fetch-blob": "^3.1.2"
},
"engines": {
"node": ">=12.20.0"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -8648,13 +8691,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-subset": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz",
"integrity": "sha512-6Ybun0IkarhmEqxXCNw/C0bna6Zb/TkfUX9UbwJtK6ObwAVCxmAP308WWTHviM/zAqXk05cdhYsUsZeGQh99iw==",
"dev": true,
"license": "MIT"
},
"node_modules/is-symbol": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
@@ -9208,17 +9244,6 @@
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-fetch-mock": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz",
"integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==",
"dev": true,
"license": "MIT",
"dependencies": {
"cross-fetch": "^3.0.4",
"promise-polyfill": "^8.1.3"
}
},
"node_modules/jest-haste-map": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz",
@@ -9958,14 +9983,6 @@
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
"license": "MIT"
},
"node_modules/lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
"dev": true,
"license": "MIT"
},
"node_modules/lodash.isobject": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
@@ -9985,13 +10002,6 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"license": "MIT"
},
"node_modules/lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
"integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
"dev": true,
"license": "MIT"
},
"node_modules/lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
@@ -10312,6 +10322,27 @@
"license": "MIT",
"optional": true
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"deprecated": "Use your platform's native DOMException instead",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"license": "MIT",
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-exports-info": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz",
@@ -10342,49 +10373,22 @@
}
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
"dev": true,
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
"data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
},
"engines": {
"node": "4.x || >=6.0.0"
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-fetch/node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"dev": true,
"license": "MIT"
},
"node_modules/node-fetch/node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"dev": true,
"license": "BSD-2-Clause"
},
"node_modules/node-fetch/node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dev": true,
"license": "MIT",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
}
},
"node_modules/node-int64": {
@@ -10758,13 +10762,6 @@
"dev": true,
"license": "ISC"
},
"node_modules/path-to-regexp": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.4.0.tgz",
"integrity": "sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w==",
"dev": true,
"license": "MIT"
},
"node_modules/path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -10998,13 +10995,6 @@
"asap": "~2.0.6"
}
},
"node_modules/promise-polyfill": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.3.0.tgz",
"integrity": "sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==",
"dev": true,
"license": "MIT"
},
"node_modules/promise-retry": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
@@ -11076,17 +11066,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/querystring": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz",
"integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==",
"deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.4.x"
}
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -11434,6 +11413,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/regexparam": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/regexparam/-/regexparam-3.0.0.tgz",
"integrity": "sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/regexpu-core": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz",
@@ -12594,16 +12583,6 @@
"node": ">=16"
}
},
"node_modules/tr46": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
"integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
"dev": true,
"license": "MIT",
"dependencies": {
"punycode": "^2.1.0"
}
},
"node_modules/traverse": {
"version": "0.6.11",
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.11.tgz",
@@ -13223,6 +13202,16 @@
"makeerror": "1.0.12"
}
},
"node_modules/web-streams-polyfill": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
}
},
"node_modules/webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
@@ -13263,25 +13252,6 @@
"node": ">=18"
}
},
"node_modules/whatwg-url": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
"integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
"webidl-conversions": "^4.0.2"
}
},
"node_modules/whatwg-url/node_modules/webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
"dev": true,
"license": "BSD-2-Clause"
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+6 -6
View File
@@ -48,6 +48,7 @@
"typeface-open-sans": "1.1.13"
},
"devDependencies": {
"@fetch-mock/jest": "0.2.20",
"@testing-library/jest-dom": "6.9.1",
"@testing-library/react": "12.1.5",
"@testing-library/react-hooks": "8.0.1",
@@ -65,23 +66,22 @@
"@types/qs": "6.14.0",
"@types/react": "17.0.91",
"@types/react-dom": "17.0.26",
"@typescript-eslint/eslint-plugin": "8.56.0",
"@typescript-eslint/parser": "8.56.0",
"@vitejs/plugin-legacy": "7.2.1",
"@vitejs/plugin-react": "5.1.4",
"csstype": "3.2.3",
"@typescript-eslint/eslint-plugin": "8.56.0",
"@typescript-eslint/parser": "8.56.0",
"eslint": "8.57.1",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-jest": "29.15.0",
"eslint-plugin-prettier": "5.5.5",
"eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "5.2.0",
"fetch-mock": "9.11.0",
"fetch-mock": "12.6.0",
"identity-obj-proxy": "3.0.0",
"jest": "30.2.0",
"jest-environment-jsdom": "30.2.0",
"jest-fetch-mock": "3.0.3",
"node-fetch": "2.7.0",
"node-fetch": "3.3.2",
"prettier": "3.8.1",
"sass": "1.97.3",
"terser": "5.46.0",
@@ -110,7 +110,7 @@
"!src/Models/*.ts"
],
"preset": "ts-jest/presets/js-with-ts",
"testEnvironment": "jest-environment-jsdom",
"testEnvironment": "<rootDir>/src/testEnvironment.ts",
"transformIgnorePatterns": [
"node_modules/(?!(react-hotkeys-hook|react-idle-timer)/)"
],
+3 -3
View File
@@ -1,6 +1,6 @@
import { render, within } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { mockMatchMedia } from "__fixtures__/matchMedia";
import { EmptyAPIResponse } from "__fixtures__/Fetch";
@@ -39,8 +39,8 @@ beforeEach(() => {
}));
global.ResizeObserverEntry = jest.fn();
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(EmptyAPIResponse()),
});
});
+24 -19
View File
@@ -2,11 +2,11 @@ import { CommonOptions, FetchGet, FetchRetryConfig } from "./Fetch";
import merge from "lodash.merge";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
beforeEach(() => {
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
status: 200,
body: "ok",
});
@@ -14,7 +14,7 @@ beforeEach(() => {
afterEach(() => {
jest.restoreAllMocks();
fetchMock.reset();
fetchMock.mockReset();
});
describe("Fetch", () => {
@@ -23,15 +23,15 @@ describe("Fetch", () => {
};
const methodOptions: { [key: string]: RequestInit } = {
FetchGet: { method: "GET", mode: "cors" },
FetchGet: { method: "get", mode: "cors" },
};
for (const [name, func] of Object.entries(tests)) {
it(`${name}: passes '{credentials: include}' to all requests`, async () => {
const request = func("http://example.com/", {}, jest.fn());
await expect(request).resolves.toMatchObject({ status: 200 });
expect(fetchMock.lastUrl()).toBe("http://example.com/");
expect(fetchMock.lastOptions()).toEqual(
expect(fetchMock.callHistory.lastCall()?.url).toBe("http://example.com/");
expect(fetchMock.callHistory.lastCall()?.options).toEqual(
merge({}, CommonOptions, methodOptions[name]),
);
});
@@ -45,8 +45,8 @@ describe("Fetch", () => {
() => {},
);
await expect(request).resolves.toMatchObject({ status: 200 });
expect(fetchMock.lastUrl()).toBe("http://example.com/");
expect(fetchMock.lastOptions()).toEqual(
expect(fetchMock.callHistory.lastCall()?.url).toBe("http://example.com/");
expect(fetchMock.callHistory.lastCall()?.options).toEqual(
merge(
{},
CommonOptions,
@@ -67,8 +67,8 @@ describe("Fetch", () => {
() => {},
);
await expect(request).resolves.toMatchObject({ status: 200 });
expect(fetchMock.lastUrl()).toBe("http://example.com/");
expect(fetchMock.lastOptions()).toEqual(
expect(fetchMock.callHistory.lastCall()?.url).toBe("http://example.com/");
expect(fetchMock.callHistory.lastCall()?.options).toEqual(
merge({}, CommonOptions, methodOptions[name], {
credentials: "omit",
redirect: "follow",
@@ -78,36 +78,41 @@ describe("Fetch", () => {
}
it("FetchGet switches to no-cors for the last retry", async () => {
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
throws: new Error("Fetch error"),
});
const request = FetchGet("http://example.com", {}, jest.fn());
await expect(request).rejects.toThrow("Fetch error");
expect(fetchMock.calls()).toHaveLength(FetchRetryConfig.retries + 1);
expect(fetchMock.calls().map((r) => r[1])).toMatchObject(
expect(fetchMock.callHistory.calls()).toHaveLength(
FetchRetryConfig.retries + 1,
);
expect(fetchMock.callHistory.calls().map((r) => r?.options)).toMatchObject(
Array.from(Array(FetchRetryConfig.retries + 1).keys(), (i) => ({
mode: i < FetchRetryConfig.retries ? "cors" : "no-cors",
credentials: "include",
})),
);
// ensure that the the second to last call was with cors
expect(fetchMock.calls()[fetchMock.calls().length - 2][1]).toMatchObject({
expect(
fetchMock.callHistory.calls()[fetchMock.callHistory.calls().length - 2]
?.options,
).toMatchObject({
mode: "cors",
credentials: "include",
});
// ensure that the last call was with no-cors
expect(fetchMock.lastOptions()).toMatchObject({
expect(fetchMock.callHistory.lastCall()?.options).toMatchObject({
mode: "no-cors",
credentials: "include",
});
});
it("FetchGet calls beforeRetry before each retry", async () => {
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
throws: new Error("Fetch error"),
});
+86 -82
View File
@@ -2,7 +2,7 @@ import { act } from "react-dom/test-utils";
import { render, fireEvent, screen, waitFor } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { MockAlertGroup, MockAlert } from "__fixtures__/Alerts";
import type { APIAlertT, APIAlertGroupT } from "Models/APITypes";
@@ -70,8 +70,8 @@ beforeEach(() => {
foo: ["bar", "baz"],
};
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockReset();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -84,7 +84,7 @@ beforeEach(() => {
});
afterEach(() => {
fetchMock.resetHistory();
fetchMock.mockReset();
jest.clearAllTimers();
jest.clearAllMocks();
jest.restoreAllMocks();
@@ -106,7 +106,7 @@ const renderAndClick = async () => {
const badge = screen.getByRole("img", { hidden: true }).parentElement;
if (badge) fireEvent.click(badge);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
};
@@ -133,21 +133,16 @@ describe("<AlertAck />", () => {
});
it("uses faExclamationCircle after failed fetch", async () => {
fetchMock.mock(
"*",
{
status: 500,
body: "error message",
},
{
overwriteRoutes: true,
},
);
fetchMock.mockReset();
fetchMock.route("*", {
status: 500,
body: "error message",
});
renderAlertAck();
const badge = screen.getByRole("img", { hidden: true }).parentElement;
if (badge) fireEvent.click(badge);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
await waitFor(() => {
expect(screen.getByRole("img", { hidden: true })).toHaveClass(
@@ -157,21 +152,16 @@ describe("<AlertAck />", () => {
});
it("resets faExclamationCircle after 20s", async () => {
fetchMock.mock(
"*",
{
status: 500,
body: "error message",
},
{
overwriteRoutes: true,
},
);
fetchMock.mockReset();
fetchMock.route("*", {
status: 500,
body: "error message",
});
renderAlertAck();
const badge = screen.getByRole("img", { hidden: true }).parentElement;
if (badge) fireEvent.click(badge);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
await waitFor(() => {
expect(screen.getByRole("img", { hidden: true })).toHaveClass(
@@ -195,7 +185,7 @@ describe("<AlertAck />", () => {
const badge = screen.getByRole("img", { hidden: true }).parentElement;
if (badge) fireEvent.click(badge);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
await waitFor(() => {
expect(screen.getByRole("img", { hidden: true })).toHaveClass(
@@ -206,10 +196,10 @@ describe("<AlertAck />", () => {
it("sends a POST request on click", async () => {
await renderAndClick();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.lastOptions()).toMatchObject({
method: "POST",
headers: { "Content-Type": "application/json" },
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.lastCall()?.options).toMatchObject({
method: "post",
headers: { "content-type": "application/json" },
});
});
@@ -238,22 +228,22 @@ describe("<AlertAck />", () => {
};
await renderAndClick();
expect(fetchMock.calls()).toHaveLength(2);
expect(fetchMock.calls()[0][0]).toBe(
expect(fetchMock.callHistory.calls()).toHaveLength(2);
expect(fetchMock.callHistory.calls()[0]?.url).toBe(
"http://m1.example.com/api/v2/silences",
);
expect(fetchMock.calls()[0][1]).toMatchObject({
method: "POST",
expect(fetchMock.callHistory.calls()[0]?.options).toMatchObject({
method: "post",
credentials: "same-origin",
headers: { "X-Cluster": "c1" },
headers: { "x-cluster": "c1" },
});
expect(fetchMock.calls()[1][0]).toBe(
expect(fetchMock.callHistory.calls()[1]?.url).toBe(
"http://m3.example.com/api/v2/silences",
);
expect(fetchMock.calls()[1][1]).toMatchObject({
method: "POST",
expect(fetchMock.callHistory.calls()[1]?.options).toMatchObject({
method: "post",
credentials: "include",
headers: { "X-Cluster": "c2" },
headers: { "x-cluster": "c2" },
});
});
@@ -282,11 +272,11 @@ describe("<AlertAck />", () => {
};
await renderAndClick();
expect(fetchMock.calls()).toHaveLength(2);
expect(fetchMock.calls()[0][0]).toBe(
expect(fetchMock.callHistory.calls()).toHaveLength(2);
expect(fetchMock.callHistory.calls()[0]?.url).toBe(
"http://m2.example.com/api/v2/silences",
);
expect(fetchMock.calls()[1][0]).toBe(
expect(fetchMock.callHistory.calls()[1]?.url).toBe(
"http://m4.example.com/api/v2/silences",
);
});
@@ -297,16 +287,16 @@ describe("<AlertAck />", () => {
fireEvent.click(button!);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
fireEvent.click(button!);
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
});
it("sends correct payload", async () => {
fetchMock.mock(
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -319,7 +309,9 @@ describe("<AlertAck />", () => {
silenceFormStore.data.setAuthor("karma/ui");
await renderAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
expect(
JSON.parse((fetchMock.callHistory.lastCall()?.options as any).body),
).toEqual({
comment: "COMMENT",
createdBy: "karma/ui",
endsAt: "2000-02-01T00:02:03.000Z",
@@ -349,7 +341,9 @@ describe("<AlertAck />", () => {
},
});
await renderAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
expect(
JSON.parse((fetchMock.callHistory.lastCall()?.options as any).body),
).toEqual({
comment: "comment",
createdBy: "me",
endsAt: "2000-02-01T00:03:57.000Z",
@@ -379,7 +373,9 @@ describe("<AlertAck />", () => {
},
});
await renderAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
expect(
JSON.parse((fetchMock.callHistory.lastCall()?.options as any).body),
).toEqual({
comment:
"ACK! This alert was acknowledged using karma on Tue, 01 Feb 2000 00:00:00 GMT",
createdBy: "me",
@@ -410,7 +406,9 @@ describe("<AlertAck />", () => {
},
});
await renderAndClick();
const comment = JSON.parse((fetchMock.lastOptions() as any).body).comment;
const comment = JSON.parse(
(fetchMock.callHistory.lastCall()?.options as any).body,
).comment;
expect(comment).not.toEqual(
"ACK! This alert was acknowledged using karma on Tue Feb 01 2000 00:00:00 GMT",
);
@@ -433,7 +431,9 @@ describe("<AlertAck />", () => {
},
});
await renderAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
expect(
JSON.parse((fetchMock.callHistory.lastCall()?.options as any).body),
).toEqual({
comment: "FOO: bar",
createdBy: "auth@example.com",
endsAt: "2000-02-01T00:03:42.000Z",
@@ -465,7 +465,9 @@ describe("<AlertAck />", () => {
});
silenceFormStore.data.setAuthor("bob@example.com");
await renderAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
expect(
JSON.parse((fetchMock.callHistory.lastCall()?.options as any).body),
).toEqual({
comment: "FOO: bar",
createdBy: "bob@example.com",
endsAt: "2000-02-01T00:03:42.000Z",
@@ -496,7 +498,9 @@ describe("<AlertAck />", () => {
});
silenceFormStore.data.setAuthor("");
await renderAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
expect(
JSON.parse((fetchMock.callHistory.lastCall()?.options as any).body),
).toEqual({
comment: "FOO: bar",
createdBy: "me",
endsAt: "2000-02-01T00:03:42.000Z",
@@ -515,25 +519,25 @@ describe("<AlertAck />", () => {
it("sends POST request to /api/v2/silences", async () => {
await renderAndClick();
const uri = fetchMock.calls()[0][0];
const uri = fetchMock.callHistory.calls()[0]?.url;
expect(uri).toBe("http://localhost/api/v2/silences");
});
it("will retry on another cluster member after 500 response", async () => {
fetchMock.reset();
fetchMock.mock("http://m1.example.com/api/v2/silences", {
fetchMock.mockReset();
fetchMock.route("http://m1.example.com/api/v2/silences", {
status: 500,
body: "error message",
});
fetchMock.mock("http://m2.example.com/api/v2/silences", {
fetchMock.route("http://m2.example.com/api/v2/silences", {
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ silenceID: "123" }),
});
fetchMock.mock("http://m3.example.com/api/v2/silences", {
fetchMock.route("http://m3.example.com/api/v2/silences", {
status: 500,
body: "error message",
});
fetchMock.mock("http://m4.example.com/api/v2/silences", {
fetchMock.route("http://m4.example.com/api/v2/silences", {
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ silenceID: "456" }),
});
@@ -564,36 +568,36 @@ describe("<AlertAck />", () => {
const button = container.querySelector("span.badge");
fireEvent.click(button!);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(4);
expect(fetchMock.calls()[0][0]).toBe(
expect(fetchMock.callHistory.calls()).toHaveLength(4);
expect(fetchMock.callHistory.calls()[0]?.url).toBe(
"http://m1.example.com/api/v2/silences",
);
expect(fetchMock.calls()[1][0]).toBe(
expect(fetchMock.callHistory.calls()[1]?.url).toBe(
"http://m2.example.com/api/v2/silences",
);
expect(fetchMock.calls()[2][0]).toBe(
expect(fetchMock.callHistory.calls()[2]?.url).toBe(
"http://m3.example.com/api/v2/silences",
);
expect(fetchMock.calls()[3][0]).toBe(
expect(fetchMock.callHistory.calls()[3]?.url).toBe(
"http://m4.example.com/api/v2/silences",
);
});
it("will retry on another cluster member after fetch failure", async () => {
fetchMock.reset();
fetchMock.mock("http://m1.example.com/api/v2/silences", {
fetchMock.mockReset();
fetchMock.route("http://m1.example.com/api/v2/silences", {
throws: new TypeError("failed to fetch"),
});
fetchMock.mock("http://m2.example.com/api/v2/silences", {
fetchMock.route("http://m2.example.com/api/v2/silences", {
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ silenceID: "123" }),
});
fetchMock.mock("http://m3.example.com/api/v2/silences", {
fetchMock.route("http://m3.example.com/api/v2/silences", {
throws: new TypeError("failed to fetch"),
});
fetchMock.mock("http://m4.example.com/api/v2/silences", {
fetchMock.route("http://m4.example.com/api/v2/silences", {
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ silenceID: "123" }),
});
@@ -624,22 +628,22 @@ describe("<AlertAck />", () => {
const button = container.querySelector("span.badge");
fireEvent.click(button!);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(4);
expect(fetchMock.calls()[0][0]).toBe(
expect(fetchMock.callHistory.calls()).toHaveLength(4);
expect(fetchMock.callHistory.calls()[0]?.url).toBe(
"http://m1.example.com/api/v2/silences",
);
expect(fetchMock.calls()[1][0]).toBe(
expect(fetchMock.callHistory.calls()[1]?.url).toBe(
"http://m2.example.com/api/v2/silences",
);
expect(fetchMock.calls()[2][0]).toBe(
expect(fetchMock.callHistory.calls()[2]?.url).toBe(
"http://m3.example.com/api/v2/silences",
);
expect(fetchMock.calls()[3][0]).toBe(
expect(fetchMock.callHistory.calls()[3]?.url).toBe(
"http://m4.example.com/api/v2/silences",
);
});
@@ -671,10 +675,10 @@ describe("<AlertAck />", () => {
const button = container.querySelector("span.badge");
fireEvent.click(button!);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.calls()[0][0]).toBe(
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()[0]?.url).toBe(
"http://am1.example.com/api/v2/silences",
);
expect(consoleSpy).toHaveBeenCalledTimes(1);
+60 -60
View File
@@ -2,7 +2,7 @@ import { act } from "react-dom/test-utils";
import { render } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { useInView } from "react-intersection-observer";
@@ -73,15 +73,15 @@ beforeEach(() => {
});
afterEach(() => {
fetchMock.resetHistory();
fetchMock.reset();
fetchMock.mockClear();
fetchMock.mockReset();
jest.useRealTimers();
});
describe("<AlertHistory />", () => {
it("send a correct payload with empty grid", async () => {
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -99,10 +99,10 @@ describe("<AlertHistory />", () => {
<AlertHistory group={group} grid={grid}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.calls()[0][1]?.body).toStrictEqual(
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()[0]?.options?.body).toStrictEqual(
JSON.stringify({
sources: [
"https://secure.example.com/graph",
@@ -115,8 +115,8 @@ describe("<AlertHistory />", () => {
});
it("send a correct payload with non-empty grid", async () => {
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -132,10 +132,10 @@ describe("<AlertHistory />", () => {
<AlertHistory group={group} grid={grid}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.calls()[0][1]?.body).toStrictEqual(
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()[0]?.options?.body).toStrictEqual(
JSON.stringify({
sources: [
"https://secure.example.com/graph",
@@ -148,8 +148,8 @@ describe("<AlertHistory />", () => {
});
it("send a correct payload with @cluster grid", async () => {
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -167,10 +167,10 @@ describe("<AlertHistory />", () => {
<AlertHistory group={group} grid={grid}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.calls()[0][1]?.body).toStrictEqual(
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()[0]?.options?.body).toStrictEqual(
JSON.stringify({
sources: [
"https://secure.example.com/graph",
@@ -183,8 +183,8 @@ describe("<AlertHistory />", () => {
});
it("send a correct payload with shared labels", async () => {
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -204,10 +204,10 @@ describe("<AlertHistory />", () => {
<AlertHistory group={group} grid={grid}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.calls()[0][1]?.body).toStrictEqual(
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()[0]?.options?.body).toStrictEqual(
JSON.stringify({
sources: [
"https://secure.example.com/graph",
@@ -226,8 +226,8 @@ describe("<AlertHistory />", () => {
});
it("matches snapshot with empty response", async () => {
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -243,16 +243,16 @@ describe("<AlertHistory />", () => {
<AlertHistory group={group} grid={grid}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(asFragment()).toMatchSnapshot();
unmount();
});
it("matches snapshot with rainbow response", async () => {
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -268,17 +268,17 @@ describe("<AlertHistory />", () => {
<AlertHistory group={group} grid={grid}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(asFragment()).toMatchSnapshot();
unmount();
});
it("doesn't fetch when not in view", async () => {
// Verifies that react-intersection-observer prevents fetch when component is outside viewport
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -299,17 +299,17 @@ describe("<AlertHistory />", () => {
<AlertHistory group={group} grid={grid}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
unmount();
expect(fetchMock.calls()).toHaveLength(0);
expect(fetchMock.callHistory.calls()).toHaveLength(0);
});
it("fetches when component transitions from out-of-view to in-view", async () => {
// Verifies that react-intersection-observer triggers fetch when component becomes visible
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -330,9 +330,9 @@ describe("<AlertHistory />", () => {
<AlertHistory group={group} grid={grid}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(0);
expect(fetchMock.callHistory.calls()).toHaveLength(0);
(useInView as jest.MockedFunction<typeof useInView>).mockReturnValue([
jest.fn(),
@@ -341,16 +341,16 @@ describe("<AlertHistory />", () => {
rerender(<AlertHistory group={group} grid={grid}></AlertHistory>);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
unmount();
});
it("fetches an update after 300 seconds", async () => {
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -372,28 +372,28 @@ describe("<AlertHistory />", () => {
<AlertHistory group={group} grid={grid}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
await act(async () => {
jest.advanceTimersByTime(1000 * 299);
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
await act(async () => {
jest.advanceTimersByTime(1000 * 2);
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(2);
expect(fetchMock.callHistory.calls()).toHaveLength(2);
unmount();
});
it("handles responses with errors", async () => {
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -409,16 +409,16 @@ describe("<AlertHistory />", () => {
<AlertHistory group={group} grid={grid}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(asFragment()).toMatchSnapshot();
unmount();
});
it("handles fetch errors", async () => {
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
status: 500,
@@ -434,9 +434,9 @@ describe("<AlertHistory />", () => {
<AlertHistory group={group} grid={grid}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(asFragment()).toMatchSnapshot();
unmount();
});
@@ -567,8 +567,8 @@ describe("<AlertHistory />", () => {
};
it(`${testCase.title}`, async () => {
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -583,7 +583,7 @@ describe("<AlertHistory />", () => {
<AlertHistory group={g} grid={gr}></AlertHistory>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
const rects = Array.from(container.querySelectorAll("rect")).map(
+4 -4
View File
@@ -2,7 +2,7 @@ import { act } from "react-dom/test-utils";
import { render, fireEvent } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { EmptyAPIResponse } from "__fixtures__/Fetch";
@@ -48,14 +48,14 @@ afterEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
jest.useRealTimers();
fetchMock.reset();
fetchMock.mockReset();
});
const MockEmptyAPIResponseWithoutFilters = () => {
const response = EmptyAPIResponse();
response.filters = [];
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
status: 200,
body: JSON.stringify(response),
});
@@ -2,7 +2,7 @@ import { act } from "react-dom/test-utils";
import { render, fireEvent } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { MockAlert, MockAlertGroup } from "__fixtures__/Alerts";
import {
@@ -465,8 +465,8 @@ describe("<AlertGroup /> renderConfig", () => {
});
it("uses 'z-index: 100' style after setIsMenuOpen() is called on any Alert", async () => {
fetchMock.reset();
fetchMock.mock("*", { body: "" });
fetchMock.mockReset();
fetchMock.route("*", { body: "" });
const promise = Promise.resolve();
MockAlerts(5, 5);
@@ -555,8 +555,8 @@ describe("<AlertGroup /> card theme", () => {
});
it("renders AlertHistory when enabled", async () => {
fetchMock.reset();
fetchMock.mock(
fetchMock.mockReset();
fetchMock.route(
"/history.json",
{
headers: { "Content-Type": "application/json" },
@@ -574,11 +574,11 @@ describe("<AlertGroup /> card theme", () => {
group.stateCount = { active: 5, suppressed: 0, unprocessed: 0 };
const { container } = renderAlertGroup(jest.fn());
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(container.innerHTML).toMatch(/alert-history/);
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.calls()[0][0]).toBe("/history.json");
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()[0]?.url).toContain("/history.json");
});
it("doesn't render AlertHistory when disabled", () => {
@@ -2,7 +2,7 @@ import { act } from "react-dom/test-utils";
import { render, fireEvent } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { MockGrid } from "__fixtures__/Stories";
import { MockThemeContextWithoutAnimations } from "__fixtures__/Theme";
@@ -25,8 +25,8 @@ declare let document: any;
declare let window: any;
beforeEach(() => {
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify([]),
});
@@ -1,6 +1,6 @@
import { render, screen, fireEvent } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { MockThemeContext } from "__fixtures__/Theme";
import { useFetchGetMock } from "__fixtures__/useFetchGet";
@@ -10,8 +10,8 @@ import { MultiGridConfiguration } from "./MultiGridConfiguration";
let settingsStore: Settings;
beforeEach(() => {
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify([]),
});
@@ -1,6 +1,6 @@
import { render } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { MockThemeContext } from "__fixtures__/Theme";
import { Settings } from "Stores/Settings";
@@ -8,8 +8,8 @@ import { ThemeContext } from "Components/Theme";
import { Configuration } from ".";
beforeEach(() => {
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
status: 200,
body: JSON.stringify([]),
});
@@ -17,7 +17,7 @@ beforeEach(() => {
afterEach(() => {
jest.restoreAllMocks();
fetchMock.reset();
fetchMock.mockReset();
});
describe("<Configuration />", () => {
@@ -1,6 +1,6 @@
import { render, screen, fireEvent } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { MockThemeContext } from "__fixtures__/Theme";
import { AlertStore } from "Stores/AlertStore";
@@ -16,15 +16,15 @@ beforeEach(() => {
alertStore = new AlertStore([]);
settingsStore = new Settings(null);
onHide.mockClear();
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify([]),
});
});
afterEach(() => {
jest.restoreAllMocks();
fetchMock.reset();
fetchMock.mockReset();
});
const renderModalContent = () => {
+4 -4
View File
@@ -2,7 +2,7 @@ import { act } from "react-dom/test-utils";
import { render, screen, fireEvent } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { MockThemeContext } from "__fixtures__/Theme";
import { AlertStore } from "Stores/AlertStore";
@@ -18,15 +18,15 @@ beforeEach(() => {
settingsStore = new Settings(null);
jest.useFakeTimers();
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify([]),
});
});
afterEach(() => {
jest.restoreAllMocks();
fetchMock.reset();
fetchMock.mockReset();
document.body.className = "";
});
+4 -4
View File
@@ -2,7 +2,7 @@ import { act } from "react-dom/test-utils";
import { render, screen } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { useIdleTimer } from "react-idle-timer";
@@ -73,8 +73,8 @@ beforeEach(() => {
clusters: { dev: ["dev"] },
});
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(EmptyAPIResponse()),
});
});
@@ -84,7 +84,7 @@ afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
});
fetchMock.reset();
fetchMock.mockReset();
});
const renderNavbar = (fixedTop?: boolean) => {
@@ -2,7 +2,7 @@ import { act } from "react-dom/test-utils";
import { render, fireEvent } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { useFetchGetMock } from "__fixtures__/useFetchGet";
import { MockSilence } from "__fixtures__/Alerts";
@@ -63,7 +63,7 @@ afterEach(() => {
localStorage.setItem("fetchConfig.interval", "");
global.window.innerWidth = 1024;
fetchMock.reset();
fetchMock.mockReset();
});
const MockSilenceList = (count: number): APIManagedSilenceT[] => {
@@ -523,7 +523,7 @@ describe("<SilenceDelete />", () => {
cancelGet: jest.fn(),
});
fetchMock.mock("*", {
fetchMock.route("*", {
status: 200,
body: "ok",
});
@@ -554,10 +554,10 @@ describe("<SilenceDelete />", () => {
await act(async () => {
jest.advanceTimersByTime(2 * 60);
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(3);
expect(fetchMock.callHistory.calls()).toHaveLength(3);
const closeBtn = container.querySelector(".btn-close");
if (closeBtn) fireEvent.click(closeBtn);
@@ -611,7 +611,7 @@ describe("<SilenceDelete />", () => {
cancelGet: jest.fn(),
});
fetchMock.mock("*", {
fetchMock.route("*", {
status: 200,
body: "ok",
});
@@ -662,10 +662,10 @@ describe("<SilenceDelete />", () => {
await act(async () => {
jest.advanceTimersByTime(2 * 60);
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(2);
expect(fetchMock.callHistory.calls()).toHaveLength(2);
const closeBtn = container.querySelector(".btn-close");
if (closeBtn) fireEvent.click(closeBtn);
@@ -693,7 +693,7 @@ describe("<SilenceDelete />", () => {
cancelGet: jest.fn(),
});
fetchMock.mock("*", {
fetchMock.route("*", {
status: 200,
body: "ok",
});
@@ -715,7 +715,7 @@ describe("<SilenceDelete />", () => {
await act(async () => {
jest.advanceTimersByTime(60);
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
PressKey("Escape", 27);
@@ -781,30 +781,30 @@ describe("<SilenceDelete />", () => {
clusters: { am: ["am1", "am2", "am3"], failed: ["am4"] },
});
fetchMock.reset();
fetchMock.mock("http://m1.example.com/api/v2/silence/1", {
fetchMock.mockReset();
fetchMock.route("http://m1.example.com/api/v2/silence/1", {
throws: new TypeError("failed to fetch"),
});
fetchMock.mock("http://m2.example.com/api/v2/silence/1", {
fetchMock.route("http://m2.example.com/api/v2/silence/1", {
status: 502,
body: "Bad Gateway",
});
fetchMock.mock("http://m3.example.com/api/v2/silence/1", {
fetchMock.route("http://m3.example.com/api/v2/silence/1", {
status: 200,
body: "OK",
});
fetchMock.mock("http://m1.example.com/api/v2/silence/2", {
fetchMock.route("http://m1.example.com/api/v2/silence/2", {
throws: "error text",
});
fetchMock.mock("http://m2.example.com/api/v2/silence/2", {
fetchMock.route("http://m2.example.com/api/v2/silence/2", {
status: 200,
body: "OK",
});
fetchMock.mock("http://m4.example.com/api/v2/silence/3", {
fetchMock.route("http://m4.example.com/api/v2/silence/3", {
status: 400,
body: "Bad Request",
});
fetchMock.mock("http://m4.example.com/api/v2/silence/4", {
fetchMock.route("http://m4.example.com/api/v2/silence/4", {
throws: new TypeError("failed to fetch"),
});
@@ -866,11 +866,11 @@ describe("<SilenceDelete />", () => {
await act(async () => {
jest.advanceTimersByTime(10 * 60);
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(7);
const uris = fetchMock.calls().map((c) => c[0]);
expect(fetchMock.callHistory.calls()).toHaveLength(7);
const uris = fetchMock.callHistory.calls().map((c) => c?.url);
expect(uris).toContainEqual("http://m1.example.com/api/v2/silence/1");
expect(uris).toContainEqual("http://m1.example.com/api/v2/silence/2");
expect(uris).toContainEqual("http://m4.example.com/api/v2/silence/3");
@@ -905,8 +905,8 @@ describe("<SilenceDelete />", () => {
clusters: { am: ["am1"] },
});
fetchMock.reset();
fetchMock.mock("http://m1.example.com/api/v2/silence/1", {
fetchMock.mockReset();
fetchMock.route("http://m1.example.com/api/v2/silence/1", {
status: 500,
body: "Internal Server Error",
});
@@ -948,7 +948,7 @@ describe("<SilenceDelete />", () => {
await act(async () => {
jest.advanceTimersByTime(10 * 60);
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
const errorDisplay = document.body.querySelector(".bg-dark.text-white");
@@ -2,7 +2,7 @@ import { act } from "react-dom/test-utils";
import { render } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { AlertStore } from "Stores/AlertStore";
import { SilenceFormStore, NewClusterRequest } from "Stores/SilenceFormStore";
@@ -43,8 +43,8 @@ beforeEach(() => {
]),
});
fetchMock.resetHistory();
fetchMock.mock(
fetchMock.mockClear();
fetchMock.route(
"*",
{
headers: { "Content-Type": "application/json" },
@@ -58,7 +58,7 @@ beforeEach(() => {
afterEach(() => {
jest.restoreAllMocks();
fetchMock.resetHistory();
fetchMock.mockClear();
});
const renderSilenceSubmitProgress = () => {
@@ -83,29 +83,28 @@ describe("<SilenceSubmitProgress />", () => {
it("sends a request on mount", async () => {
renderSilenceSubmitProgress();
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
});
it("appends /api/v2/silences to the passed URI", async () => {
renderSilenceSubmitProgress();
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
const uri = fetchMock.calls()[0][0];
const uri = fetchMock.callHistory.calls()[0]?.url;
expect(uri).toBe("http://localhost/api/v2/silences");
});
it("sends correct JSON payload", async () => {
renderSilenceSubmitProgress();
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
const payload = fetchMock.calls()[0][1];
const payload = fetchMock.callHistory.calls()[0]?.options;
expect(payload).toMatchObject({
method: "POST",
headers: { "Content-Type": "application/json", foo: "bar" },
method: "post",
body: JSON.stringify({
matchers: [],
startsAt: "now",
@@ -114,6 +113,10 @@ describe("<SilenceSubmitProgress />", () => {
comment: "fake payload",
}),
});
// Check headers - stored as plain object
const headers = payload?.headers as Record<string, string>;
expect(headers["content-type"]).toBe("application/json");
expect(headers["foo"]).toBe("bar");
});
it("uses CORS credentials from alertmanager config", async () => {
@@ -122,21 +125,23 @@ describe("<SilenceSubmitProgress />", () => {
alertStore.data.setUpstreams(upstreams);
renderSilenceSubmitProgress();
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()[0][0]).toBe("http://localhost/api/v2/silences");
expect(fetchMock.calls()[0][1]).toMatchObject({
expect(fetchMock.callHistory.calls()[0]?.url).toBe(
"http://localhost/api/v2/silences",
);
expect(fetchMock.callHistory.calls()[0]?.options).toMatchObject({
credentials: "same-origin",
method: "POST",
method: "post",
});
});
it("will retry on another cluster member after fetch failure", async () => {
fetchMock.reset();
fetchMock.mock("http://am2.example.com/api/v2/silences", {
fetchMock.mockReset();
fetchMock.route("http://am2.example.com/api/v2/silences", {
throws: new TypeError("failed to fetch"),
});
fetchMock.mock("http://am1.example.com/api/v2/silences", {
fetchMock.route("http://am1.example.com/api/v2/silences", {
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ silenceID: "123456789" }),
});
@@ -190,23 +195,23 @@ describe("<SilenceSubmitProgress />", () => {
/>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()[0][0]).toBe(
expect(fetchMock.callHistory.calls()[0]?.url).toBe(
"http://am2.example.com/api/v2/silences",
);
expect(fetchMock.calls()).toHaveLength(2);
expect(fetchMock.calls()[1][0]).toBe(
expect(fetchMock.callHistory.calls()).toHaveLength(2);
expect(fetchMock.callHistory.calls()[1]?.url).toBe(
"http://am1.example.com/api/v2/silences",
);
});
it("will use error message from last failed cluster member", async () => {
fetchMock.reset();
fetchMock.mock("http://am2.example.com/api/v2/silences", {
fetchMock.mockReset();
fetchMock.route("http://am2.example.com/api/v2/silences", {
throws: new TypeError("failed to fetch from am2"),
});
fetchMock.mock("http://am1.example.com/api/v2/silences", {
fetchMock.route("http://am1.example.com/api/v2/silences", {
throws: new TypeError("failed to fetch from am1"),
});
alertStore.data.setUpstreams({
@@ -259,9 +264,9 @@ describe("<SilenceSubmitProgress />", () => {
/>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(2);
expect(fetchMock.callHistory.calls()).toHaveLength(2);
expect(silenceFormStore.data.requestsByCluster.ha).toMatchObject({
isDone: true,
error: "failed to fetch from am1",
@@ -310,9 +315,9 @@ describe("<SilenceSubmitProgress />", () => {
/>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()[0][0]).toBe(
expect(fetchMock.callHistory.calls()[0]?.url).toBe(
"http://am1.example.com/api/v2/silences",
);
expect(consoleSpy).toHaveBeenCalledTimes(1);
@@ -347,9 +352,9 @@ describe("<SilenceSubmitProgress />", () => {
/>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(0);
expect(fetchMock.callHistory.calls()).toHaveLength(0);
expect(consoleSpy).toHaveBeenCalledTimes(2);
});
@@ -411,10 +416,10 @@ describe("<SilenceSubmitProgress />", () => {
/>,
);
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.calls()[0][0]).toBe(
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()[0]?.url).toBe(
"http://am1.example.com/api/v2/silences",
);
expect(logs).toEqual(['Alertmanager instance "am2" is read-only']);
@@ -478,7 +483,7 @@ describe("<SilenceSubmitProgress />", () => {
silenceFormStore={silenceFormStore}
/>,
);
expect(fetchMock.calls()).toHaveLength(0);
expect(fetchMock.callHistory.calls()).toHaveLength(0);
expect(logs).toEqual([
'Alertmanager instance "am2" is read-only',
'Alertmanager instance "am1" is read-only',
@@ -489,7 +494,7 @@ describe("<SilenceSubmitProgress />", () => {
it("renders silence link on successful fetch", async () => {
renderSilenceSubmitProgress();
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(
silenceFormStore.data.requestsByCluster.mockAlertmanager,
@@ -502,14 +507,14 @@ describe("<SilenceSubmitProgress />", () => {
});
it("sets error icon on failed fetch", async () => {
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
status: 500,
body: "error message",
});
renderSilenceSubmitProgress();
await act(async () => {
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
expect(
silenceFormStore.data.requestsByCluster.mockAlertmanager,
@@ -2,7 +2,7 @@ import { act } from "react-dom/test-utils";
import { render, fireEvent } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { MockThemeContext } from "__fixtures__/Theme";
import { ThemeContext } from "Components/Theme";
@@ -21,15 +21,15 @@ beforeEach(() => {
silenceFormStore = new SilenceFormStore();
jest.useFakeTimers();
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify([]),
});
});
afterEach(() => {
jest.restoreAllMocks();
fetchMock.reset();
fetchMock.mockReset();
document.body.className = "";
});
+44 -43
View File
@@ -3,43 +3,40 @@ import { act } from "react-dom/test-utils";
import { renderHook } from "@testing-library/react-hooks";
import { render } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { useFetchAny, UpstreamT } from "./useFetchAny";
describe("useFetchAny", () => {
beforeAll(() => {
fetchMock.mock("http://localhost/ok", "body ok");
fetchMock.mock("http://localhost/ok/json", {
beforeEach(() => {
fetchMock.mockReset();
fetchMock.route("http://localhost/ok", "body ok");
fetchMock.route("http://localhost/ok/json", {
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ status: "ok" }),
});
fetchMock.mock("http://localhost/500", {
fetchMock.route("http://localhost/500", {
status: 500,
body: "fake error",
});
fetchMock.mock("http://localhost/401", 401);
fetchMock.mock("http://localhost/error", {
fetchMock.route("http://localhost/401", 401);
fetchMock.route("http://localhost/error", {
throws: new TypeError("failed to fetch"),
});
fetchMock.mock("http://localhost/unknown", {
throws: "foo",
fetchMock.route("http://localhost/unknown", {
throws: new Error("foo"),
});
});
beforeEach(() => {
fetchMock.resetHistory();
});
afterEach(() => {
fetchMock.resetHistory();
fetchMock.mockClear();
});
it("does nothing on empty upstream list", async () => {
const upstreams: UpstreamT[] = [];
const { result } = renderHook(() => useFetchAny(upstreams));
expect(fetchMock.calls()).toHaveLength(0);
expect(fetchMock.callHistory.calls()).toHaveLength(0);
expect(result.current.inProgress).toBe(false);
});
@@ -49,10 +46,10 @@ describe("useFetchAny", () => {
await waitForNextUpdate();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.lastUrl()).toBe("http://localhost/ok");
expect(fetchMock.lastOptions()).toMatchObject({
method: "GET",
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.lastCall()?.url).toBe("http://localhost/ok");
expect(fetchMock.callHistory.lastCall()?.options).toMatchObject({
method: "get",
credentials: "include",
mode: "cors",
redirect: "follow",
@@ -63,17 +60,17 @@ describe("useFetchAny", () => {
const upstreams: UpstreamT[] = [
{
uri: "http://localhost/ok",
options: { method: "POST", credentials: "same-origin" },
options: { method: "post", credentials: "same-origin" },
},
];
const { waitForNextUpdate } = renderHook(() => useFetchAny(upstreams));
await waitForNextUpdate();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.lastUrl()).toBe("http://localhost/ok");
expect(fetchMock.lastOptions()).toMatchObject({
method: "POST",
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.lastCall()?.url).toBe("http://localhost/ok");
expect(fetchMock.callHistory.lastCall()?.options).toMatchObject({
method: "post",
credentials: "same-origin",
mode: "cors",
redirect: "follow",
@@ -86,9 +83,9 @@ describe("useFetchAny", () => {
await waitForNextUpdate();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.lastUrl()).toBe("http://localhost/ok");
expect(fetchMock.lastOptions()).toMatchObject({
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.lastCall()?.url).toBe("http://localhost/ok");
expect(fetchMock.callHistory.lastCall()?.options).toMatchObject({
mode: "cors",
credentials: "include",
redirect: "follow",
@@ -204,13 +201,13 @@ describe("useFetchAny", () => {
await waitForNextUpdate();
expect(result.current.response).toBe(null);
expect(result.current.error).toBe("unknown error: foo");
expect(result.current.error).toBe("foo");
expect(result.current.inProgress).toBe(false);
expect(result.current.responseURI).toBe(null);
});
it("doesn't update response after cleanup", async () => {
fetchMock.mock(
fetchMock.route(
"http://localhost/slow/ok",
new Promise((res) => setTimeout(() => res("ok"), 1000)),
);
@@ -230,11 +227,11 @@ describe("useFetchAny", () => {
const { unmount } = render(<Component />);
unmount();
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
it("doesn't update error on 500 response after cleanup", async () => {
fetchMock.mock("http://localhost/slow/500", {
fetchMock.route("http://localhost/slow/500", {
delay: 1000,
status: 500,
body: "error",
@@ -257,11 +254,11 @@ describe("useFetchAny", () => {
unmount();
});
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
it("doesn't update error on failed response after cleanup", async () => {
fetchMock.mock("http://localhost/slow/error", {
fetchMock.route("http://localhost/slow/error", {
delay: 1000,
throws: new TypeError("failed to fetch"),
});
@@ -283,7 +280,7 @@ describe("useFetchAny", () => {
unmount();
});
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
it("doesn't retry on success", async () => {
@@ -298,8 +295,8 @@ describe("useFetchAny", () => {
await waitForNextUpdate();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.calls()[0][0]).toBe("http://localhost/ok");
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()[0]?.url).toBe("http://localhost/ok");
expect(result.current.response).toBe("body ok");
expect(result.current.error).toBe(null);
@@ -319,10 +316,12 @@ describe("useFetchAny", () => {
await waitForNextUpdate();
expect(fetchMock.calls()).toHaveLength(3);
expect(fetchMock.calls()[0][0]).toBe("http://localhost/500");
expect(fetchMock.calls()[1][0]).toBe("http://localhost/error");
expect(fetchMock.calls()[2][0]).toBe("http://localhost/ok");
expect(fetchMock.callHistory.calls()).toHaveLength(3);
expect(fetchMock.callHistory.calls()[0]?.url).toBe("http://localhost/500");
expect(fetchMock.callHistory.calls()[1]?.url).toBe(
"http://localhost/error",
);
expect(fetchMock.callHistory.calls()[2]?.url).toBe("http://localhost/ok");
expect(result.current.response).toBe("body ok");
expect(result.current.error).toBe(null);
@@ -342,9 +341,11 @@ describe("useFetchAny", () => {
await waitForNextUpdate();
expect(fetchMock.calls()).toHaveLength(2);
expect(fetchMock.calls()[0][0]).toBe("http://localhost/500");
expect(fetchMock.calls()[1][0]).toBe("http://localhost/ok/json");
expect(fetchMock.callHistory.calls()).toHaveLength(2);
expect(fetchMock.callHistory.calls()[0]?.url).toBe("http://localhost/500");
expect(fetchMock.callHistory.calls()[1]?.url).toBe(
"http://localhost/ok/json",
);
expect(result.current.response).toMatchObject({ status: "ok" });
expect(result.current.error).toBe(null);
+24 -27
View File
@@ -3,32 +3,29 @@ import { act } from "react-dom/test-utils";
import { renderHook } from "@testing-library/react-hooks";
import { render } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { useFetchDelete } from "./useFetchDelete";
describe("useFetchDelete", () => {
beforeAll(() => {
fetchMock.mock("http://localhost/ok", "body ok");
fetchMock.mock("http://localhost/401", 401);
fetchMock.mock("http://localhost/500", {
beforeEach(() => {
fetchMock.mockReset();
fetchMock.route("http://localhost/ok", "body ok");
fetchMock.route("http://localhost/401", 401);
fetchMock.route("http://localhost/500", {
status: 500,
body: "fake error",
});
fetchMock.mock("http://localhost/error", {
fetchMock.route("http://localhost/error", {
throws: new TypeError("failed to fetch"),
});
fetchMock.mock("http://localhost/unknown", {
throws: "foo",
fetchMock.route("http://localhost/unknown", {
throws: new Error("foo"),
});
});
beforeEach(() => {
fetchMock.resetHistory();
});
afterEach(() => {
fetchMock.resetHistory();
fetchMock.mockClear();
});
const EmptyOptions = {};
@@ -40,10 +37,10 @@ describe("useFetchDelete", () => {
await waitForNextUpdate();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.lastUrl()).toBe("http://localhost/ok");
expect(fetchMock.lastOptions()).toMatchObject({
method: "DELETE",
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.lastCall()?.url).toBe("http://localhost/ok");
expect(fetchMock.callHistory.lastCall()?.options).toMatchObject({
method: "delete",
});
});
@@ -54,9 +51,9 @@ describe("useFetchDelete", () => {
await waitForNextUpdate();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.lastUrl()).toBe("http://localhost/ok");
expect(fetchMock.lastOptions()).toMatchObject({
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.lastCall()?.url).toBe("http://localhost/ok");
expect(fetchMock.callHistory.lastCall()?.options).toMatchObject({
mode: "cors",
credentials: "include",
redirect: "follow",
@@ -139,12 +136,12 @@ describe("useFetchDelete", () => {
await waitForNextUpdate();
expect(result.current.response).toBe(null);
expect(result.current.error).toBe("unknown error: foo");
expect(result.current.error).toBe("foo");
expect(result.current.isDeleting).toBe(false);
});
it("doesn't update response after cleanup", async () => {
fetchMock.mock(
fetchMock.route(
"http://localhost/slow/ok",
new Promise((res) => setTimeout(() => res("ok"), 1000)),
);
@@ -166,11 +163,11 @@ describe("useFetchDelete", () => {
const { unmount } = render(<Component />);
unmount();
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
it("doesn't update error on 500 response after cleanup", async () => {
fetchMock.mock("http://localhost/slow/500", {
fetchMock.route("http://localhost/slow/500", {
delay: 1000,
status: 500,
body: "error",
@@ -195,11 +192,11 @@ describe("useFetchDelete", () => {
unmount();
});
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
it("doesn't update error on failed response after cleanup", async () => {
fetchMock.mock("http://localhost/slow/error", {
fetchMock.route("http://localhost/slow/error", {
delay: 1000,
throws: new TypeError("failed to fetch"),
});
@@ -223,6 +220,6 @@ describe("useFetchDelete", () => {
unmount();
});
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
});
+42 -41
View File
@@ -3,7 +3,7 @@ import { act as actReact } from "react-dom/test-utils";
import { renderHook, act } from "@testing-library/react-hooks";
import { render } from "@testing-library/react";
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { FetchRetryConfig } from "Common/Fetch";
import { useFetchGet } from "./useFetchGet";
@@ -11,27 +11,24 @@ import { useFetchGet } from "./useFetchGet";
jest.unmock("./useFetchGet");
describe("useFetchGet", () => {
beforeAll(() => {
fetchMock.mock("http://localhost/ok", {
beforeEach(() => {
jest.useFakeTimers();
fetchMock.mockReset();
fetchMock.route("http://localhost/ok", {
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ status: "ok" }),
});
fetchMock.mock("http://localhost/401", 401);
fetchMock.mock("http://localhost/error", {
fetchMock.route("http://localhost/401", 401);
fetchMock.route("http://localhost/error", {
throws: new TypeError("failed to fetch"),
});
fetchMock.mock("http://localhost/unknown", {
throws: "foo",
fetchMock.route("http://localhost/unknown", {
throws: new Error("foo"),
});
});
beforeEach(() => {
jest.useFakeTimers();
fetchMock.resetHistory();
});
afterEach(() => {
fetchMock.resetHistory();
fetchMock.mockClear();
});
it("sends a GET request", async () => {
@@ -41,10 +38,10 @@ describe("useFetchGet", () => {
await waitForNextUpdate();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.lastUrl()).toBe("http://localhost/ok");
expect(fetchMock.lastOptions()).toMatchObject({
method: "GET",
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.lastCall()?.url).toBe("http://localhost/ok");
expect(fetchMock.callHistory.lastCall()?.options).toMatchObject({
method: "get",
});
});
@@ -55,9 +52,9 @@ describe("useFetchGet", () => {
await waitForNextUpdate();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.lastUrl()).toBe("http://localhost/ok");
expect(fetchMock.lastOptions()).toMatchObject({
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.lastCall()?.url).toBe("http://localhost/ok");
expect(fetchMock.callHistory.lastCall()?.options).toMatchObject({
mode: "cors",
credentials: "include",
redirect: "follow",
@@ -69,15 +66,15 @@ describe("useFetchGet", () => {
useFetchGet<string>("http://localhost/ok", { autorun: false }),
);
expect(fetchMock.calls()).toHaveLength(0);
expect(fetchMock.callHistory.calls()).toHaveLength(0);
act(() => {
result.current.get();
});
await waitForNextUpdate();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.lastUrl()).toBe("http://localhost/ok");
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(fetchMock.callHistory.lastCall()?.url).toBe("http://localhost/ok");
});
it("will retry failed requests", async () => {
@@ -121,12 +118,16 @@ describe("useFetchGet", () => {
expect(result.current.isRetrying).toBe(false);
expect(result.current.retryCount).toBe(FetchRetryConfig.retries + 1);
expect(fetchMock.calls()).toHaveLength(FetchRetryConfig.retries + 1);
expect(fetchMock.lastUrl()).toBe("http://localhost/error");
expect(fetchMock.callHistory.calls()).toHaveLength(
FetchRetryConfig.retries + 1,
);
expect(fetchMock.callHistory.lastCall()?.url).toBe(
"http://localhost/error",
);
//verify headers for each request
for (let i = 0; i <= FetchRetryConfig.retries; i++) {
expect(fetchMock.calls()[i][1]).toMatchObject({
expect(fetchMock.callHistory.calls()[i]?.options).toMatchObject({
mode: i < FetchRetryConfig.retries ? "cors" : "no-cors",
credentials: "include",
redirect: "follow",
@@ -153,7 +154,7 @@ describe("useFetchGet", () => {
});
it("error is updated after 500 response with JSON body", async () => {
fetchMock.mock("http://localhost/500/json", {
fetchMock.route("http://localhost/500/json", {
status: 500,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ status: "error" }),
@@ -172,7 +173,7 @@ describe("useFetchGet", () => {
});
it("error is updated after 500 response with plain body", async () => {
fetchMock.mock("http://localhost/500/text", {
fetchMock.route("http://localhost/500/text", {
status: 500,
body: "error",
});
@@ -245,13 +246,13 @@ describe("useFetchGet", () => {
}
expect(result.current.response).toBe(null);
expect(result.current.error).toBe("unknown error: foo");
expect(result.current.error).toBe("foo");
expect(result.current.isLoading).toBe(false);
expect(result.current.isRetrying).toBe(false);
});
it("error is updated on uparsable JSON", async () => {
fetchMock.mock("http://localhost/json/invalid", {
fetchMock.route("http://localhost/json/invalid", {
headers: { "Content-Type": "application/json" },
body: "this is not a valid JSON body",
});
@@ -270,14 +271,14 @@ describe("useFetchGet", () => {
expect(result.current.response).toBe(null);
expect(result.current.error).toBe(
"invalid json response body at http://localhost/json/invalid reason: Unexpected token 'h', \"this is not\"... is not valid JSON",
"unknown error: SyntaxError: Unexpected token 'h', \"this is not\"... is not valid JSON",
);
expect(result.current.isLoading).toBe(false);
expect(result.current.isRetrying).toBe(false);
});
it("doesn't update response on 200 response after cleanup", async () => {
fetchMock.mock("http://localhost/slow/ok", {
fetchMock.route("http://localhost/slow/ok", {
delay: 1000,
body: JSON.stringify({ status: "ok" }),
});
@@ -302,12 +303,12 @@ describe("useFetchGet", () => {
for (let i = 0; i <= FetchRetryConfig.retries; i++) {
jest.runOnlyPendingTimers();
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
}
});
it("doesn't update error on 500 response after cleanup", async () => {
fetchMock.mock("http://localhost/slow/500", {
fetchMock.route("http://localhost/slow/500", {
delay: 1000,
status: 500,
body: JSON.stringify({ status: "error" }),
@@ -333,12 +334,12 @@ describe("useFetchGet", () => {
for (let i = 0; i <= FetchRetryConfig.retries; i++) {
jest.runOnlyPendingTimers();
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
}
});
it("doesn't update error on failed response after cleanup", async () => {
fetchMock.mock("http://localhost/slow/error", {
fetchMock.route("http://localhost/slow/error", {
delay: 1000,
throws: new TypeError("failed to fetch"),
});
@@ -363,12 +364,12 @@ describe("useFetchGet", () => {
for (let i = 0; i <= FetchRetryConfig.retries; i++) {
jest.runOnlyPendingTimers();
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
}
});
it("doesn't update error on unparsable JSON after cleanup", async () => {
fetchMock.mock("http://localhost/slow/json/invalid", {
fetchMock.route("http://localhost/slow/json/invalid", {
delay: 1000,
headers: { "Content-Type": "application/json" },
body: "this is not a valid JSON body",
@@ -393,11 +394,11 @@ describe("useFetchGet", () => {
});
jest.runOnlyPendingTimers();
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
it("doesn't update response after cleanup", async () => {
fetchMock.mock("http://localhost/slow/text", {
fetchMock.route("http://localhost/slow/text", {
delay: 1000,
body: "ok",
});
@@ -421,7 +422,7 @@ describe("useFetchGet", () => {
});
jest.runOnlyPendingTimers();
await fetchMock.flush(true);
await fetchMock.callHistory.flush(true);
});
it("doesn't update response after cleanup on slow body read", async () => {
+60 -52
View File
@@ -1,4 +1,4 @@
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { EmptyAPIResponse } from "__fixtures__/Fetch";
import { MockGroup } from "__fixtures__/Stories";
@@ -14,12 +14,12 @@ import {
declare let global: any;
beforeEach(() => {
fetchMock.reset();
fetchMock.mockReset();
});
afterEach(() => {
jest.restoreAllMocks();
fetchMock.reset();
fetchMock.mockReset();
});
describe("AlertStore.data", () => {
@@ -530,8 +530,8 @@ describe("AlertStore.fetch", () => {
it("fetch() works with valid response", async () => {
const response = EmptyAPIResponse();
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
@@ -540,14 +540,14 @@ describe("AlertStore.fetch", () => {
store.fetch("", false, "", "", false, {}, 5, {}),
).resolves.toBeUndefined();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(store.status.value).toEqual(AlertStoreStatuses.Idle);
expect(store.info.version).toBe("fakeVersion");
});
it("fetch() handles response with error correctly", async () => {
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify({ error: "Fetch error" }),
});
@@ -556,7 +556,7 @@ describe("AlertStore.fetch", () => {
store.fetch("", false, "", "", false, {}, 5, {}),
).resolves.toBeUndefined();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
expect(store.status.value).toEqual(AlertStoreStatuses.Failure);
expect(store.info.version).toBe("unknown");
});
@@ -565,8 +565,8 @@ describe("AlertStore.fetch", () => {
const consoleSpy = jest
.spyOn(console, "trace")
.mockImplementation(() => {});
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
throws: new Error("fetch error"),
});
@@ -575,7 +575,7 @@ describe("AlertStore.fetch", () => {
store.fetch("", false, "", "", false, {}, 5, {}),
).resolves.toHaveProperty("error");
expect(fetchMock.calls()).toHaveLength(10);
expect(fetchMock.callHistory.calls()).toHaveLength(10);
expect(store.status.value).toEqual(AlertStoreStatuses.Failure);
expect(store.info.version).toBe("unknown");
// there should be a trace of the error
@@ -586,51 +586,51 @@ describe("AlertStore.fetch", () => {
jest.spyOn(console, "trace").mockImplementation(() => {});
const store = new AlertStore([]);
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
throws: new Error("fetch error"),
});
await expect(
store.fetch("", false, "", "", false, {}, 5, {}),
).resolves.toHaveProperty("error");
expect(fetchMock.calls()).toHaveLength(10);
expect(fetchMock.callHistory.calls()).toHaveLength(10);
});
it("fetch() retry counter is reset after successful fetch", async () => {
jest.spyOn(console, "trace").mockImplementation(() => {});
const store = new AlertStore(["label=value"]);
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
throws: new Error("fetch error"),
});
await expect(
store.fetch("", false, "", "", false, {}, 5, {}),
).resolves.toHaveProperty("error");
expect(fetchMock.calls()).toHaveLength(10);
expect(fetchMock.callHistory.calls()).toHaveLength(10);
const response = EmptyAPIResponse();
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
await expect(
store.fetch("", false, "", "", false, {}, 5, {}),
).resolves.toBeUndefined();
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.callHistory.calls()).toHaveLength(1);
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
throws: new Error("fetch error"),
});
await expect(
store.fetch("", false, "", "", false, {}, 5, {}),
).resolves.toHaveProperty("error");
expect(fetchMock.calls()).toHaveLength(10);
expect(fetchMock.callHistory.calls()).toHaveLength(10);
});
it("fetch() reloads the page after if auth middleware is detected", async () => {
@@ -659,8 +659,8 @@ describe("AlertStore.fetch", () => {
store.filters.setFilterValues([NewUnappliedFilter("foo")]);
jest.spyOn(console, "trace").mockImplementation(() => {});
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
throws: new Error("fetch error"),
});
@@ -672,8 +672,8 @@ describe("AlertStore.fetch", () => {
it("stored settings are updated if needed after fetch", async () => {
const response = EmptyAPIResponse();
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
@@ -717,8 +717,8 @@ describe("AlertStore.fetch", () => {
it("wants to reload page after new version is returned in the API", async () => {
const response = EmptyAPIResponse();
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
const store = new AlertStore(["label=value"]);
@@ -728,8 +728,8 @@ describe("AlertStore.fetch", () => {
expect(store.info.upgradeReady).toBe(false);
response.version = "newFakeVersion";
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
await expect(
@@ -793,17 +793,19 @@ describe("AlertStore.fetch", () => {
it("uses correct query args with gridSortReverse=false", async () => {
const response = EmptyAPIResponse();
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
const store = new AlertStore(["label=value"]);
await expect(
store.fetch("", false, "sortOrder", "sortLabel", false, {}, 5, {}),
).resolves.toBeUndefined();
expect(fetchMock.calls().length).toEqual(1);
expect(fetchMock.calls()[0][0]).toBe("/alerts.json");
expect(JSON.parse(fetchMock.calls()[0][1]?.body as string)).toStrictEqual({
expect(fetchMock.callHistory.calls().length).toEqual(1);
expect(fetchMock.callHistory.calls()[0]?.url).toContain("/alerts.json");
expect(
JSON.parse(fetchMock.callHistory.calls()[0]?.options?.body as string),
).toStrictEqual({
filters: ["label=value"],
gridLabel: "",
gridLimits: {},
@@ -818,17 +820,19 @@ describe("AlertStore.fetch", () => {
it("uses correct query args with gridSortReverse=true", async () => {
const response = EmptyAPIResponse();
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
const store = new AlertStore(["label=value"]);
await expect(
store.fetch("cluster", true, "sortOrder", "sortLabel", true, {}, 5, {}),
).resolves.toBeUndefined();
expect(fetchMock.calls().length).toEqual(1);
expect(fetchMock.calls()[0][0]).toBe("/alerts.json");
expect(JSON.parse(fetchMock.calls()[0][1]?.body as string)).toStrictEqual({
expect(fetchMock.callHistory.calls().length).toEqual(1);
expect(fetchMock.callHistory.calls()[0]?.url).toContain("/alerts.json");
expect(
JSON.parse(fetchMock.callHistory.calls()[0]?.options?.body as string),
).toStrictEqual({
filters: ["label=value"],
gridLabel: "cluster",
gridLimits: {},
@@ -843,8 +847,8 @@ describe("AlertStore.fetch", () => {
it("uses correct query args with limits", async () => {
const response = EmptyAPIResponse();
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
const store = new AlertStore(["label=value"]);
@@ -866,9 +870,11 @@ describe("AlertStore.fetch", () => {
{ "1234567890": 7, "1234567891": 1 },
),
).resolves.toBeUndefined();
expect(fetchMock.calls().length).toEqual(1);
expect(fetchMock.calls()[0][0]).toBe("/alerts.json");
expect(JSON.parse(fetchMock.calls()[0][1]?.body as string)).toStrictEqual({
expect(fetchMock.callHistory.calls().length).toEqual(1);
expect(fetchMock.callHistory.calls()[0]?.url).toContain("/alerts.json");
expect(
JSON.parse(fetchMock.callHistory.calls()[0]?.options?.body as string),
).toStrictEqual({
filters: ["label=value"],
gridLabel: "cluster",
gridLimits: { bar: 7 },
@@ -904,8 +910,8 @@ describe("AlertStore.fetch", () => {
stateCount: { unprocessed: 0, active: 3, suppressed: 0 },
},
];
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
@@ -923,9 +929,11 @@ describe("AlertStore.fetch", () => {
{ g1: 7, g2: 1, g4: 6 },
),
).resolves.toBeUndefined();
expect(fetchMock.calls().length).toEqual(1);
expect(fetchMock.calls()[0][0]).toBe("/alerts.json");
expect(JSON.parse(fetchMock.calls()[0][1]?.body as string)).toStrictEqual({
expect(fetchMock.callHistory.calls().length).toEqual(1);
expect(fetchMock.callHistory.calls()[0]?.url).toContain("/alerts.json");
expect(
JSON.parse(fetchMock.callHistory.calls()[0]?.options?.body as string),
).toStrictEqual({
filters: ["label=value"],
gridLabel: "cluster",
gridLimits: { bar: 7 },
+5 -5
View File
@@ -1,4 +1,4 @@
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { EmptyAPIResponse } from "__fixtures__/Fetch";
import { DefaultsBase64 } from "__fixtures__/Defaults";
@@ -34,8 +34,8 @@ it("renders without crashing with missing defaults div", () => {
const response = EmptyAPIResponse();
response.filters = [];
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
@@ -62,8 +62,8 @@ it("renders without crashing with defaults present", () => {
const response = EmptyAPIResponse();
response.filters = [];
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
+3 -3
View File
@@ -1,4 +1,4 @@
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { EmptyAPIResponse } from "__fixtures__/Fetch";
import { mockMatchMedia } from "__fixtures__/matchMedia";
@@ -37,8 +37,8 @@ it("loads ResizeObserver polyfill if needed", () => {
const response = EmptyAPIResponse();
response.filters = [];
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
+3 -3
View File
@@ -1,4 +1,4 @@
import fetchMock from "fetch-mock";
import fetchMock from "@fetch-mock/jest";
import { EmptyAPIResponse } from "__fixtures__/Fetch";
import { mockMatchMedia } from "__fixtures__/matchMedia";
@@ -46,8 +46,8 @@ it("doesn't load ResizeObserver polyfill if not needed", () => {
const response = EmptyAPIResponse();
response.filters = [];
fetchMock.reset();
fetchMock.mock("*", {
fetchMock.mockReset();
fetchMock.route("*", {
body: JSON.stringify(response),
});
+6
View File
@@ -2,6 +2,8 @@ import React from "react";
import "@testing-library/jest-dom";
import fetchMock, { manageFetchMockGlobally } from "@fetch-mock/jest";
import { useInView } from "react-intersection-observer";
import { createMocks as createIdleTimerMocks } from "react-idle-timer";
@@ -15,6 +17,10 @@ import { useFetchGet } from "Hooks/useFetchGet";
createIdleTimerMocks();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
manageFetchMockGlobally(jest as any);
fetchMock.mockGlobal();
configure({
enforceActions: "always",
//computedRequiresReaction: true,
+11
View File
@@ -0,0 +1,11 @@
import { TestEnvironment } from "jest-environment-jsdom";
export default class CustomTestEnvironment extends TestEnvironment {
async setup() {
await super.setup();
this.global.Request = Request;
this.global.Response = Response;
this.global.ReadableStream = ReadableStream;
this.global.fetch = fetch;
}
}