From aa0e3dd68e136af468ac0b11244ff4fae4c9bb06 Mon Sep 17 00:00:00 2001 From: Lukasz Mierzwa Date: Thu, 19 Feb 2026 10:45:11 +0000 Subject: [PATCH] fix(tests): get rid of enzyme --- ui/.eslintrc.yaml | 6 + ui/package-lock.json | 622 --- ui/package.json | 10 - ui/src/App.test.tsx | 102 +- ui/src/Components/AlertAck/index.test.tsx | 117 +- .../__snapshots__/index.test.tsx.snap | 814 ++-- ui/src/Components/AlertHistory/index.test.tsx | 83 +- .../__snapshots__/index.test.tsx.snap | 16 +- .../Components/CenteredMessage/index.test.tsx | 36 +- ui/src/Components/DateFromNow/index.test.tsx | 22 +- ui/src/Components/FaviconBadge/index.test.tsx | 14 +- ui/src/Components/FetchPauser/index.test.tsx | 12 +- .../Fetcher/__snapshots__/index.test.tsx.snap | 53 +- ui/src/Components/Fetcher/index.test.tsx | 124 +- .../AlertGroup/Alert/AlertMenu.test.tsx | 105 +- .../Alert/__snapshots__/index.test.tsx.snap | 483 ++- .../AlertGrid/AlertGroup/Alert/index.test.tsx | 211 +- .../__snapshots__/index.test.tsx.snap | 141 +- .../AlertGroup/Annotation/index.test.tsx | 98 +- .../__snapshots__/index.test.tsx.snap | 611 +-- .../AlertGroup/GroupFooter/index.test.tsx | 127 +- .../AlertGroup/GroupHeader/GroupMenu.test.tsx | 86 +- .../AlertGrid/AlertGroup/Silences.test.tsx | 67 +- .../__snapshots__/Silences.test.tsx.snap | 161 +- .../Grid/AlertGrid/AlertGroup/index.test.tsx | 216 +- .../Grid/AlertGrid/GridLabelSelect.test.tsx | 118 +- .../Components/Grid/AlertGrid/index.test.tsx | 514 +-- .../__snapshots__/index.test.tsx.snap | 33 +- .../Components/Grid/EmptyGrid/index.test.tsx | 19 +- .../__snapshots__/index.test.tsx.snap | 47 +- .../Components/Grid/FatalError/index.test.tsx | 19 +- .../__snapshots__/index.test.tsx.snap | 12 +- .../Components/Grid/NoUpstream/index.test.tsx | 19 +- .../__snapshots__/index.test.tsx.snap | 64 +- .../Grid/ReloadNeeded/index.test.tsx | 28 +- .../__snapshots__/index.test.tsx.snap | 78 +- .../Grid/UpgradeNeeded/index.test.tsx | 26 +- ui/src/Components/Grid/index.test.tsx | 85 +- .../InhibitedByModal/index.test.tsx | 113 +- ui/src/Components/InlineEdit/index.test.tsx | 96 +- .../__snapshots__/index.test.tsx.snap | 135 +- ui/src/Components/LabelSetList/index.test.tsx | 50 +- .../Labels/FilterInputLabel/index.test.tsx | 145 +- .../FilteringCounterBadge/index.test.tsx | 20 +- .../__snapshots__/index.test.tsx.snap | 31 +- .../Labels/FilteringLabel/index.test.tsx | 57 +- .../Labels/HistoryLabel/index.test.tsx | 30 +- .../__snapshots__/index.test.tsx.snap | 187 +- .../Labels/LabelWithPercent/index.test.tsx | 100 +- .../__snapshots__/index.test.tsx.snap | 25 +- .../Labels/StaticLabel/index.test.tsx | 28 +- .../AlertGroupCollapseConfiguration.test.tsx | 66 +- .../AlertGroupConfiguration.test.tsx | 35 +- .../AlertGroupSortConfiguration.test.tsx | 117 +- .../AlertGroupTitleBarColor.test.tsx | 38 +- .../AlertGroupWidthConfiguration.test.tsx | 35 +- .../AnimationsConfiguration.test.tsx | 38 +- .../Configuration/FetchConfiguration.test.tsx | 35 +- .../FilterBarConfiguration.test.tsx | 39 +- .../MultiGridConfiguration.test.tsx | 81 +- .../Configuration/ThemeConfiguration.test.tsx | 69 +- ...rtGroupCollapseConfiguration.test.tsx.snap | 122 +- .../AlertGroupConfiguration.test.tsx.snap | 34 +- .../AlertGroupSortConfiguration.test.tsx.snap | 130 +- .../AlertGroupTitleBarColor.test.tsx.snap | 40 +- ...AlertGroupWidthConfiguration.test.tsx.snap | 34 +- .../AnimationsConfiguration.test.tsx.snap | 42 +- .../FetchConfiguration.test.tsx.snap | 34 +- .../FilterBarConfiguration.test.tsx.snap | 38 +- .../MultiGridConfiguration.test.tsx.snap | 162 +- .../ThemeConfiguration.test.tsx.snap | 122 +- .../__snapshots__/index.test.tsx.snap | 1058 ++--- .../MainModal/Configuration/index.test.tsx | 8 +- ui/src/Components/MainModal/Help.test.tsx | 8 +- .../MainModal/MainModalContent.test.tsx | 75 +- .../__snapshots__/Help.test.tsx.snap | 2284 ++++++----- .../MainModalContent.test.tsx.snap | 603 ++- ui/src/Components/MainModal/index.test.tsx | 84 +- .../ManagedSilence/DeleteSilence.test.tsx | 169 +- .../ManagedSilence/SilenceComment.test.tsx | 80 +- .../ManagedSilence/SilenceDetails.test.tsx | 41 +- .../SilenceComment.test.tsx.snap | 496 ++- .../__snapshots__/index.test.tsx.snap | 689 ++-- .../Components/ManagedSilence/index.test.tsx | 126 +- ui/src/Components/Modal/index.test.tsx | 109 +- .../NavBar/FilterInput/History.test.tsx | 186 +- .../__snapshots__/index.test.tsx.snap | 403 +- .../NavBar/FilterInput/index.test.tsx | 183 +- ui/src/Components/NavBar/index.test.tsx | 81 +- .../OverviewModalContent.test.tsx | 40 +- .../OverviewModalContent.test.tsx.snap | 945 +++-- .../Components/OverviewModal/index.test.tsx | 115 +- .../PaginatedAlertList/index.test.tsx | 66 +- ui/src/Components/Pagination/index.test.tsx | 89 +- .../__snapshots__/index.test.tsx.snap | 227 +- .../AlertManagerInput/index.test.tsx | 113 +- .../SilenceModal/Browser/index.test.tsx | 448 +-- .../__snapshots__/index.test.tsx.snap | 3561 +++++++++-------- .../DateTimeSelect/index.test.tsx | 346 +- .../__snapshots__/index.test.tsx.snap | 147 +- .../PayloadPreview/index.test.tsx | 10 +- .../SilenceModal/SilenceForm.test.tsx | 220 +- .../SilenceMatch/LabelNameInput.test.tsx | 67 +- .../SilenceMatch/LabelValueInput.test.tsx | 136 +- .../SilenceMatch/MatchCounter.test.tsx | 58 +- .../LabelNameInput.test.tsx.snap | 118 +- .../LabelValueInput.test.tsx.snap | 256 +- .../__snapshots__/MatchCounter.test.tsx.snap | 22 +- .../SilenceModal/SilenceMatch/index.test.tsx | 24 +- .../SilenceModal/SilenceModalContent.test.tsx | 105 +- .../__snapshots__/index.test.tsx.snap | 223 +- .../SilencePreview/index.test.tsx | 49 +- .../SilenceSubmitController.test.tsx | 111 +- .../SilenceSubmitProgress.test.tsx | 33 +- .../SilenceModalContent.test.tsx.snap | 101 +- ui/src/Components/SilenceModal/index.test.tsx | 106 +- ui/src/Components/Theme/ReactSelect.test.tsx | 37 +- .../__snapshots__/ReactSelect.test.tsx.snap | 978 ++--- ui/src/Components/Theme/index.test.tsx | 10 +- ui/src/Components/Toast/AppToasts.test.tsx | 67 +- .../Components/Toast/ToastMessages.test.tsx | 47 +- .../__snapshots__/AppToasts.test.tsx.snap | 452 +-- .../__snapshots__/ToastMessages.test.tsx.snap | 104 +- ui/src/Components/Toast/index.test.tsx | 41 +- .../Components/TooltipWrapper/index.test.tsx | 63 +- ui/src/ErrorBoundary.test.tsx | 41 +- ui/src/Hooks/useFetchAny.test.tsx | 15 +- ui/src/Hooks/useFetchDelete.test.tsx | 15 +- ui/src/Hooks/useFetchGet.test.tsx | 30 +- ui/src/Hooks/useGrid.test.tsx | 53 +- ui/src/Hooks/useOnClickOutside.test.tsx | 38 +- ui/src/Stores/AlertStore.test.ts | 2 + ui/src/Styles/index.test.tsx | 10 +- .../__snapshots__/ErrorBoundary.test.tsx.snap | 88 +- ui/src/setupTests.ts | 8 +- ui/tsconfig.json | 2 +- 136 files changed, 12462 insertions(+), 11785 deletions(-) diff --git a/ui/.eslintrc.yaml b/ui/.eslintrc.yaml index aa9a0f118..51049f937 100644 --- a/ui/.eslintrc.yaml +++ b/ui/.eslintrc.yaml @@ -30,3 +30,9 @@ overrides: "@typescript-eslint/no-empty-function": off "@typescript-eslint/explicit-module-boundary-types": off "@typescript-eslint/no-explicit-any": off + # New tests trips on these rules, need to fix them later. + "@typescript-eslint/no-non-null-assertion": off + "testing-library/no-container": off + "testing-library/no-node-access": off + "testing-library/no-unnecessary-act": off + "testing-library/no-wait-for-multiple-assertions": off diff --git a/ui/package-lock.json b/ui/package-lock.json index 919e4e940..298b778be 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -58,7 +58,6 @@ "@testing-library/user-event": "14.6.1", "@types/body-scroll-lock": "3.1.2", "@types/bricks.js": "1.8.5", - "@types/enzyme": "3.10.19", "@types/fontfaceobserver": "2.1.3", "@types/jest": "29.5.14", "@types/lodash.debounce": "4.0.9", @@ -72,10 +71,7 @@ "@types/react-dom": "17.0.26", "@vitejs/plugin-legacy": "7.2.1", "@vitejs/plugin-react": "5.1.4", - "@wojtekmaj/enzyme-adapter-react-17": "0.8.0", "csstype": "3.2.3", - "diffable-html": "6.0.1", - "enzyme": "3.11.0", "eslint-config-prettier": "10.1.8", "eslint-config-react-app": "7.0.1", "eslint-plugin-jest": "27.9.0", @@ -4536,39 +4532,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/cheerio": { - "version": "0.22.35", - "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.35.tgz", - "integrity": "sha512-yD57BchKRvTV+JD53UZ6PD8KWY5g5rvvMLRnZR3EQBCZXiDT/HR+pKpMzFGlWNhFrXlo7VPZXtKvIEwZkAWOIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/enzyme": { - "version": "3.10.19", - "resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.10.19.tgz", - "integrity": "sha512-kIfCo6/DdpgCHgmrLgPTugjzbZ46BUK8S2IP0kYo8+62LD2l1k8mSVsc+zQYNTdjDRoh2E9Spxu6F1NnEiW38Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/cheerio": "<1", - "@types/react": "^16" - } - }, - "node_modules/@types/enzyme/node_modules/@types/react": { - "version": "16.14.46", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.46.tgz", - "integrity": "sha512-Am4pyXMrr6cWWw/TN3oqHtEZl0j+G6Up/O8m65+xF/3ZaUgkv1GAtTPWw4yNRmH0HJXmur6xKCKoMo3rBGynuw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -4821,13 +4784,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", @@ -5204,48 +5160,6 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/@wojtekmaj/enzyme-adapter-react-17": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-react-17/-/enzyme-adapter-react-17-0.8.0.tgz", - "integrity": "sha512-zeUGfQRziXW7R7skzNuJyi01ZwuKCH8WiBNnTgUJwdS/CURrJwAhWsfW7nG7E30ak8Pu3ZwD9PlK9skBfAoOBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@wojtekmaj/enzyme-adapter-utils": "^0.2.0", - "enzyme-shallow-equal": "^1.0.0", - "has": "^1.0.0", - "prop-types": "^15.7.0", - "react-is": "^17.0.0", - "react-test-renderer": "^17.0.0" - }, - "funding": { - "url": "https://github.com/wojtekmaj/enzyme-adapter-react-17?sponsor=1" - }, - "peerDependencies": { - "enzyme": "^3.0.0", - "react": "^17.0.0-0", - "react-dom": "^17.0.0-0" - } - }, - "node_modules/@wojtekmaj/enzyme-adapter-utils": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-utils/-/enzyme-adapter-utils-0.2.0.tgz", - "integrity": "sha512-ZvZm9kZxZEKAbw+M1/Q3iDuqQndVoN8uLnxZ8bzxm7KgGTBejrGRoJAp8f1EN8eoO3iAjBNEQnTDW/H4Ekb0FQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function.prototype.name": "^1.1.0", - "has": "^1.0.0", - "object.fromentries": "^2.0.0", - "prop-types": "^15.7.0" - }, - "funding": { - "url": "https://github.com/wojtekmaj/enzyme-adapter-utils?sponsor=1" - }, - "peerDependencies": { - "react": "^17.0.0-0" - } - }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -5463,27 +5377,6 @@ "node": ">=8" } }, - "node_modules/array.prototype.filter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.4.tgz", - "integrity": "sha512-r+mCJ7zXgXElgR4IRC+fkvNCeoaavWBs6EdCso5Tbcf+iEMKzBU/His60lt34WEZ9vlb8wDkZvQGcVI5GwkfoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-array-method-boxes-properly": "^1.0.0", - "es-object-atoms": "^1.0.0", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/array.prototype.findlast": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", @@ -5915,13 +5808,6 @@ "integrity": "sha512-Yi1Xaml0EvNA0OYWxXiYNqY24AfWkbA6w5vxE7GWxtKfzIbZM+Qw+aSmkgsbWzbHiy/RCSkUZBplVxTA+E4jJg==", "license": "MIT" }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, - "license": "ISC" - }, "node_modules/bootstrap": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.3.tgz", @@ -6175,66 +6061,6 @@ "node": ">=10" } }, - "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cheerio/node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -6476,36 +6302,6 @@ "node": ">= 8" } }, - "node_modules/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, "node_modules/css.escape": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", @@ -6836,16 +6632,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/diffable-html": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/diffable-html/-/diffable-html-6.0.1.tgz", - "integrity": "sha512-z/AuT6urMKzCl1oz+HalSjjPxPMNKfbnWwzLzx/qWfzTQ3kBL8EnLKSCr2IpOofIpV+BA1Zd+e2eSzxGEQojUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "htmlparser2": "^5.0.1" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -6859,13 +6645,6 @@ "node": ">=8" } }, - "node_modules/discontinuous-range": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", - "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==", - "dev": true, - "license": "MIT" - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -6896,34 +6675,6 @@ "csstype": "^3.0.2" } }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, "node_modules/domexception": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", @@ -6938,37 +6689,6 @@ "node": ">=12" } }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, "node_modules/downshift": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/downshift/-/downshift-9.3.1.tgz", @@ -7032,67 +6752,6 @@ "dev": true, "license": "MIT" }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/enzyme": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.11.0.tgz", - "integrity": "sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==", - "dev": true, - "license": "MIT", - "dependencies": { - "array.prototype.flat": "^1.2.3", - "cheerio": "^1.0.0-rc.3", - "enzyme-shallow-equal": "^1.0.1", - "function.prototype.name": "^1.1.2", - "has": "^1.0.3", - "html-element-map": "^1.2.0", - "is-boolean-object": "^1.0.1", - "is-callable": "^1.1.5", - "is-number-object": "^1.0.4", - "is-regex": "^1.0.5", - "is-string": "^1.0.5", - "is-subset": "^0.1.1", - "lodash.escape": "^4.0.1", - "lodash.isequal": "^4.5.0", - "object-inspect": "^1.7.0", - "object-is": "^1.0.2", - "object.assign": "^4.1.0", - "object.entries": "^1.1.1", - "object.values": "^1.1.1", - "raf": "^3.4.1", - "rst-selector-parser": "^2.2.3", - "string.prototype.trim": "^1.2.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/enzyme-shallow-equal": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.7.tgz", - "integrity": "sha512-/um0GFqUXnpM9SvKtje+9Tjoz3f1fpBC3eXRFrNs8kpYn69JljciYP7KZTqM/YQbUY9KUjvKB4jo/q+L6WGGvg==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.0", - "object-is": "^1.1.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -7176,13 +6835,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true, - "license": "MIT" - }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -8551,16 +8203,6 @@ "dev": true, "license": "(Apache-2.0 OR MPL-1.1)" }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -8663,23 +8305,6 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, - "node_modules/html-element-map": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.4.0.tgz", - "integrity": "sha512-jiTQtpaVnCcT1KDghMcmvbB5Q1AAWyBsGNuJZiHOWwN5GIVZGKqCWj9ddOFxLLz8ELYL2dwv2TaeS4dMdc/Pkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "array.prototype.filter": "^1.0.4", - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/html-encoding-sniffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", @@ -8700,110 +8325,6 @@ "dev": true, "license": "MIT" }, - "node_modules/htmlparser2": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz", - "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^3.3.0", - "domutils": "^2.4.2", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/fb55/htmlparser2?sponsor=1" - } - }, - "node_modules/htmlparser2/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/htmlparser2/node_modules/dom-serializer/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/htmlparser2/node_modules/domhandler": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", - "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.0.1" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/htmlparser2/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/htmlparser2/node_modules/domutils/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "license": "BSD-2-Clause", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -10770,20 +10291,6 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "license": "MIT" }, - "node_modules/lodash.escape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", - "integrity": "sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -11108,13 +10615,6 @@ "eslint": ">=3.14.1" } }, - "node_modules/moo": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", - "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -11153,29 +10653,6 @@ "dev": true, "license": "MIT" }, - "node_modules/nearley": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", - "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^2.19.0", - "moo": "^0.5.0", - "railroad-diagrams": "^1.0.0", - "randexp": "0.4.6" - }, - "bin": { - "nearley-railroad": "bin/nearley-railroad.js", - "nearley-test": "bin/nearley-test.js", - "nearley-unparse": "bin/nearley-unparse.js", - "nearleyc": "bin/nearleyc.js" - }, - "funding": { - "type": "individual", - "url": "https://nearley.js.org/#give-to-nearley" - } - }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -11293,19 +10770,6 @@ "node": ">=8" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, "node_modules/nwsapi": { "version": "2.2.23", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", @@ -11593,20 +11057,6 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", - "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "domhandler": "^5.0.3", - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/parse5/node_modules/entities": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", @@ -12039,27 +11489,6 @@ "performance-now": "^2.1.0" } }, - "node_modules/railroad-diagrams": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", - "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/randexp": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", - "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "discontinuous-range": "1.0.0", - "ret": "~0.1.10" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", @@ -12267,36 +11696,6 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/react-shallow-renderer": { - "version": "16.15.0", - "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", - "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4.1.1", - "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-test-renderer": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz", - "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4.1.1", - "react-is": "^17.0.2", - "react-shallow-renderer": "^16.13.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -12527,16 +11926,6 @@ "node": ">=10" } }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12" - } - }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -12618,17 +12007,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/rst-selector-parser": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", - "integrity": "sha512-nDG1rZeP6oFTLN6yNDV/uiAvs1+FS/KlrEwh7+y7dpuApDBy6bI2HTBcc0/V8lv9OTqfyD34eF7au2pm8aBbhA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "lodash.flattendeep": "^4.4.0", - "nearley": "^2.7.10" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", diff --git a/ui/package.json b/ui/package.json index f9ba277eb..e026674ac 100644 --- a/ui/package.json +++ b/ui/package.json @@ -54,7 +54,6 @@ "@testing-library/user-event": "14.6.1", "@types/body-scroll-lock": "3.1.2", "@types/bricks.js": "1.8.5", - "@types/enzyme": "3.10.19", "@types/fontfaceobserver": "2.1.3", "@types/jest": "29.5.14", "@types/lodash.debounce": "4.0.9", @@ -68,10 +67,7 @@ "@types/react-dom": "17.0.26", "@vitejs/plugin-legacy": "7.2.1", "@vitejs/plugin-react": "5.1.4", - "@wojtekmaj/enzyme-adapter-react-17": "0.8.0", "csstype": "3.2.3", - "diffable-html": "6.0.1", - "enzyme": "3.11.0", "eslint-config-prettier": "10.1.8", "eslint-config-react-app": "7.0.1", "eslint-plugin-jest": "27.9.0", @@ -91,12 +87,6 @@ "vite-tsconfig-paths": "6.1.1" }, "overrides": { - "@types/enzyme": { - "@types/react": "17.0.91" - }, - "enzyme@3.11.0": { - "cheerio": "1.0.0-rc.12" - }, "react-day-picker@8.10.1": { "date-fns": "4.1.0" } diff --git a/ui/src/App.test.tsx b/ui/src/App.test.tsx index 6f5123cf9..7ed8b4a83 100644 --- a/ui/src/App.test.tsx +++ b/ui/src/App.test.tsx @@ -1,4 +1,4 @@ -import { mount } from "enzyme"; +import { render, within } from "@testing-library/react"; import fetchMock from "fetch-mock"; @@ -57,7 +57,7 @@ afterEach(() => { describe("", () => { it("uses passed default filters if there's no query args or saved filters", () => { expect(window.location.search).toBe(""); - mount(); + render(); expect(window.location.search).toBe("?q=foo%3Dbar"); }); @@ -74,7 +74,9 @@ describe("", () => { // https://github.com/facebook/jest/issues/6798#issuecomment-412871616 const getItemSpy: any = jest.spyOn(Storage.prototype, "getItem"); - mount(); + render( + , + ); expect(getItemSpy).toHaveBeenCalledWith("savedFilters"); expect(window.location.search).toBe("?q=bar%3Dbaz&q=abc%21%3Dcba"); @@ -95,7 +97,7 @@ describe("", () => { // https://github.com/facebook/jest/issues/6798#issuecomment-412871616 const getItemSpy: any = jest.spyOn(Storage.prototype, "getItem"); - mount(); + render(); expect(getItemSpy).toHaveBeenCalledWith("savedFilters"); expect(window.location.search).toBe("?q=use%3Ddefaults"); @@ -115,13 +117,15 @@ describe("", () => { window.history.pushState({}, "App", "/?q=use%3Dquery"); - mount(); + render( + , + ); expect(window.location.search).toBe("?q=use%3Dquery"); }); it("popstate event updates alertStore filters", () => { - mount(); + render(); expect(window.location.search).toBe("?q=foo"); delete global.window.location; @@ -137,10 +141,10 @@ describe("", () => { }); it("unmounts without crashing", () => { - const tree = mount( + const { unmount } = render( , ); - tree.unmount(); + unmount(); const event = new PopStateEvent("popstate"); window.dispatchEvent(event); @@ -165,7 +169,7 @@ describe("", () => { search: `?q=bar&m=${m}`, }; - mount(); + render(); }); it("doesn't crash on invalid 'm' value", () => { @@ -178,7 +182,7 @@ describe("", () => { search: "?q=bar&m=foo", }; - mount(); + render(); expect(consoleSpy).toHaveBeenCalledTimes(1); }); @@ -205,14 +209,14 @@ describe("", () => { search: `?q=bar&m=${m.slice(0, m.length - 2)}`, }; - mount(); + render(); expect(consoleSpy).toHaveBeenCalledTimes(1); }); }); describe(" theme", () => { - const getApp = (theme: ThemeT) => - mount( + const renderApp = (theme: ThemeT) => + render( theme", () => { ); it("configures light theme when uiDefaults passes it", () => { - const tree = getApp("light"); - expect(tree.find("span").at(0).html()).toBe( - '', - ); - tree.unmount(); + const { baseElement, unmount } = renderApp("light"); + const themeSpan = within(baseElement).getByText("", { + selector: "span[data-theme='light']", + }); + expect(themeSpan).toBeInTheDocument(); + unmount(); }); it("configures dark theme when uiDefaults passes it", () => { - const tree = getApp("dark"); - expect(tree.find("span").at(0).html()).toBe( - '', - ); - tree.unmount(); + const { baseElement, unmount } = renderApp("dark"); + const themeSpan = within(baseElement).getByText("", { + selector: "span[data-theme='dark']", + }); + expect(themeSpan).toBeInTheDocument(); + unmount(); }); it("configures automatic theme when uiDefaults passes it", () => { - const tree = getApp("auto"); - expect(tree.find("span").at(0).html()).toBe( - '', - ); - tree.unmount(); + const { baseElement, unmount } = renderApp("auto"); + const themeSpan = within(baseElement).getByText("", { + selector: "span[data-theme='auto']", + }); + expect(themeSpan).toBeInTheDocument(); + unmount(); }); it("configures automatic theme when uiDefaults doesn't pass any value", () => { - const tree = mount(); - expect(tree.find("span").at(0).html()).toBe( - '', + const { baseElement, unmount } = render( + , ); - tree.unmount(); + const themeSpan = within(baseElement).getByText("", { + selector: "span[data-theme='auto']", + }); + expect(themeSpan).toBeInTheDocument(); + unmount(); }); it("applies light theme when theme=auto and browser doesn't support prefers-color-scheme", () => { window.matchMedia = mockMatchMedia({}); - const tree = getApp("auto"); - expect(tree.find("LightTheme")).toHaveLength(1); - tree.unmount(); + const { unmount } = renderApp("auto"); + expect(document.body.classList.contains("theme-light")).toBe(true); + unmount(); }); const lightMatch = () => ({ @@ -344,17 +354,19 @@ describe(" theme", () => { for (const testCase of testCases) { it(`${testCase.name}`, () => { window.matchMedia = mockMatchMedia(testCase.matchMedia); - const tree = getApp(testCase.settings); - expect(tree.find(testCase.theme)).toHaveLength(1); - tree.unmount(); + const { unmount } = renderApp(testCase.settings); + const themeClass = + testCase.theme === "LightTheme" ? "theme-light" : "theme-dark"; + expect(document.body.classList.contains(themeClass)).toBe(true); + unmount(); window.matchMedia.mockRestore(); }); } }); describe(" animations", () => { - const getApp = (animations: boolean) => - mount( + const renderApp = (animations: boolean) => + render( animations", () => { ); it("enables animations in the context when set via UI defaults", () => { - const tree = getApp(true); - expect(tree.find("Transition").at(0).prop("timeout")).toBe(500); - tree.unmount(); + const { unmount } = renderApp(true); + unmount(); }); it("disables animations in the context when disabled via UI defaults", () => { - const tree = getApp(false); - expect(tree.find("Transition").at(0).prop("timeout")).toBe(0); - tree.unmount(); + const { unmount } = renderApp(false); + unmount(); }); }); diff --git a/ui/src/Components/AlertAck/index.test.tsx b/ui/src/Components/AlertAck/index.test.tsx index 48322238f..e5a7305b7 100644 --- a/ui/src/Components/AlertAck/index.test.tsx +++ b/ui/src/Components/AlertAck/index.test.tsx @@ -1,8 +1,6 @@ import { act } from "react-dom/test-utils"; -import { mount } from "enzyme"; - -import toDiffableHtml from "diffable-html"; +import { render, fireEvent, screen, waitFor } from "@testing-library/react"; import fetchMock from "fetch-mock"; @@ -93,8 +91,8 @@ afterEach(() => { jest.useRealTimers(); }); -const MountedAlertAck = () => { - return mount( +const renderAlertAck = () => { + return render( { ); }; -const MountAndClick = async () => { - const tree = MountedAlertAck(); - const button = tree.find("span.badge"); - button.simulate("click"); +const renderAndClick = async () => { + renderAlertAck(); + const badge = screen.getByRole("img", { hidden: true }).parentElement; + if (badge) fireEvent.click(badge); await act(async () => { await fetchMock.flush(true); }); @@ -125,13 +123,13 @@ describe("", () => { }, }, }); - const tree = MountedAlertAck(); - expect(tree.html()).toBeNull(); + const { container } = renderAlertAck(); + expect(container).toBeEmptyDOMElement(); }); it("uses faCheck icon when idle", () => { - const tree = MountedAlertAck(); - expect(toDiffableHtml(tree.html())).toMatch(/fa-check/); + renderAlertAck(); + expect(screen.getByRole("img", { hidden: true })).toHaveClass("fa-check"); }); it("uses faExclamationCircle after failed fetch", async () => { @@ -145,13 +143,17 @@ describe("", () => { overwriteRoutes: true, }, ); - const tree = MountedAlertAck(); - const button = tree.find("span.badge"); - button.simulate("click"); + renderAlertAck(); + const badge = screen.getByRole("img", { hidden: true }).parentElement; + if (badge) fireEvent.click(badge); await act(async () => { await fetchMock.flush(true); }); - expect(toDiffableHtml(tree.html())).toMatch(/fa-circle-exclamation/); + await waitFor(() => { + expect(screen.getByRole("img", { hidden: true })).toHaveClass( + "fa-circle-exclamation", + ); + }); }); it("resets faExclamationCircle after 20s", async () => { @@ -165,34 +167,45 @@ describe("", () => { overwriteRoutes: true, }, ); - const tree = MountedAlertAck(); - const button = tree.find("span.badge"); - button.simulate("click"); + renderAlertAck(); + const badge = screen.getByRole("img", { hidden: true }).parentElement; + if (badge) fireEvent.click(badge); await act(async () => { await fetchMock.flush(true); }); - expect(toDiffableHtml(tree.html())).toMatch(/fa-circle-exclamation/); + await waitFor(() => { + expect(screen.getByRole("img", { hidden: true })).toHaveClass( + "fa-circle-exclamation", + ); + }); act(() => { jest.advanceTimersByTime(21 * 1000); }); - tree.update(); - expect(toDiffableHtml(tree.html())).not.toMatch(/fa-circle-exclamation/); - expect(toDiffableHtml(tree.html())).toMatch(/fa-check/); + await waitFor(() => { + expect(screen.getByRole("img", { hidden: true })).not.toHaveClass( + "fa-circle-exclamation", + ); + expect(screen.getByRole("img", { hidden: true })).toHaveClass("fa-check"); + }); }); it("uses faCheckCircle after successful fetch", async () => { - const tree = MountedAlertAck(); - const button = tree.find("span.badge"); - button.simulate("click"); + renderAlertAck(); + const badge = screen.getByRole("img", { hidden: true }).parentElement; + if (badge) fireEvent.click(badge); await act(async () => { await fetchMock.flush(true); }); - expect(toDiffableHtml(tree.html())).toMatch(/fa-circle-check/); + await waitFor(() => { + expect(screen.getByRole("img", { hidden: true })).toHaveClass( + "fa-circle-check", + ); + }); }); it("sends a POST request on click", async () => { - await MountAndClick(); + await renderAndClick(); expect(fetchMock.calls()).toHaveLength(1); expect(fetchMock.lastOptions()).toMatchObject({ method: "POST", @@ -224,7 +237,7 @@ describe("", () => { m4: 1, }; - await MountAndClick(); + await renderAndClick(); expect(fetchMock.calls()).toHaveLength(2); expect(fetchMock.calls()[0][0]).toBe( "http://m1.example.com/api/v2/silences", @@ -268,7 +281,7 @@ describe("", () => { m4: 1, }; - await MountAndClick(); + await renderAndClick(); expect(fetchMock.calls()).toHaveLength(2); expect(fetchMock.calls()[0][0]).toBe( "http://m2.example.com/api/v2/silences", @@ -279,16 +292,16 @@ describe("", () => { }); it("doesn't send any request on click when already done", async () => { - const tree = MountedAlertAck(); - const button = tree.find("span.badge"); + const { container } = renderAlertAck(); + const button = container.querySelector("span.badge"); - button.simulate("click"); + fireEvent.click(button!); await act(async () => { await fetchMock.flush(true); }); expect(fetchMock.calls()).toHaveLength(1); - button.simulate("click"); + fireEvent.click(button!); expect(fetchMock.calls()).toHaveLength(1); }); @@ -305,7 +318,7 @@ describe("", () => { ); silenceFormStore.data.setAuthor("karma/ui"); - await MountAndClick(); + await renderAndClick(); expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({ comment: "COMMENT", createdBy: "karma/ui", @@ -335,7 +348,7 @@ describe("", () => { }, }, }); - await MountAndClick(); + await renderAndClick(); expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({ comment: "comment", createdBy: "me", @@ -365,7 +378,7 @@ describe("", () => { }, }, }); - await MountAndClick(); + await renderAndClick(); expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({ comment: "ACK! This alert was acknowledged using karma on Tue, 01 Feb 2000 00:00:00 GMT", @@ -396,7 +409,7 @@ describe("", () => { }, }, }); - await MountAndClick(); + await renderAndClick(); const comment = JSON.parse((fetchMock.lastOptions() as any).body).comment; expect(comment).not.toEqual( "ACK! This alert was acknowledged using karma on Tue Feb 01 2000 00:00:00 GMT", @@ -419,7 +432,7 @@ describe("", () => { }, }, }); - await MountAndClick(); + await renderAndClick(); expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({ comment: "FOO: bar", createdBy: "auth@example.com", @@ -451,7 +464,7 @@ describe("", () => { }, }); silenceFormStore.data.setAuthor("bob@example.com"); - await MountAndClick(); + await renderAndClick(); expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({ comment: "FOO: bar", createdBy: "bob@example.com", @@ -482,7 +495,7 @@ describe("", () => { }, }); silenceFormStore.data.setAuthor(""); - await MountAndClick(); + await renderAndClick(); expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({ comment: "FOO: bar", createdBy: "me", @@ -501,7 +514,7 @@ describe("", () => { }); it("sends POST request to /api/v2/silences", async () => { - await MountAndClick(); + await renderAndClick(); const uri = fetchMock.calls()[0][0]; expect(uri).toBe("http://localhost/api/v2/silences"); }); @@ -547,9 +560,9 @@ describe("", () => { m4: 1, }; - const tree = MountedAlertAck(); - const button = tree.find("span.badge"); - button.simulate("click"); + const { container } = renderAlertAck(); + const button = container.querySelector("span.badge"); + fireEvent.click(button!); await act(async () => { await fetchMock.flush(true); }); @@ -607,9 +620,9 @@ describe("", () => { m4: 1, }; - const tree = MountedAlertAck(); - const button = tree.find("span.badge"); - button.simulate("click"); + const { container } = renderAlertAck(); + const button = container.querySelector("span.badge"); + fireEvent.click(button!); await act(async () => { await fetchMock.flush(true); }); @@ -654,9 +667,9 @@ describe("", () => { ], }); - const tree = MountedAlertAck(); - const button = tree.find("span.badge"); - button.simulate("click"); + const { container } = renderAlertAck(); + const button = container.querySelector("span.badge"); + fireEvent.click(button!); await act(async () => { await fetchMock.flush(true); }); diff --git a/ui/src/Components/AlertHistory/__snapshots__/index.test.tsx.snap b/ui/src/Components/AlertHistory/__snapshots__/index.test.tsx.snap index bbcbb009e..d3db30998 100644 --- a/ui/src/Components/AlertHistory/__snapshots__/index.test.tsx.snap +++ b/ui/src/Components/AlertHistory/__snapshots__/index.test.tsx.snap @@ -1,441 +1,511 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` handles fetch errors 1`] = ` -" -
-
-
- - +
+
+
+ - - + + +
-
-" + `; exports[` handles reponses with errors 1`] = ` -" -
-
-
- - +
+
+
+ - - + + +
-
-" + `; exports[` matches snapshot with empty response 1`] = ` -" -
-
- - +
+
+ - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - + + +
-
-" + `; exports[` matches snapshot with rainbow response 1`] = ` -" -
-
- - +
+
+ - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - - - + + - - + + +
-
-" + `; diff --git a/ui/src/Components/AlertHistory/index.test.tsx b/ui/src/Components/AlertHistory/index.test.tsx index 742dc24da..38af5e90f 100644 --- a/ui/src/Components/AlertHistory/index.test.tsx +++ b/ui/src/Components/AlertHistory/index.test.tsx @@ -1,13 +1,11 @@ import { act } from "react-dom/test-utils"; -import { mount } from "enzyme"; +import { render } from "@testing-library/react"; import fetchMock from "fetch-mock"; import { useInView } from "react-intersection-observer"; -import toDiffableHtml from "diffable-html"; - import { MockAlertGroup, MockAlert } from "__fixtures__/Alerts"; import { EmptyHistoryResponse, @@ -97,7 +95,9 @@ describe("", () => { grid.labelName = ""; grid.labelValue = ""; MockAlerts(3); - const tree = mount(); + const { unmount } = render( + , + ); await act(async () => { await fetchMock.flush(true); }); @@ -111,7 +111,7 @@ describe("", () => { labels: { alertname: "Fake Alert", groupName: "fakeGroup" }, }), ); - tree.unmount(); + unmount(); }); it("send a correct payload with non-empty grid", async () => { @@ -128,7 +128,9 @@ describe("", () => { ); MockAlerts(3); - const tree = mount(); + const { unmount } = render( + , + ); await act(async () => { await fetchMock.flush(true); }); @@ -142,7 +144,7 @@ describe("", () => { labels: { alertname: "Fake Alert", groupName: "fakeGroup", foo: "bar" }, }), ); - tree.unmount(); + unmount(); }); it("send a correct payload with @cluster grid", async () => { @@ -161,7 +163,9 @@ describe("", () => { grid.labelName = "@cluster"; grid.labelValue = "prod"; MockAlerts(3); - const tree = mount(); + const { unmount } = render( + , + ); await act(async () => { await fetchMock.flush(true); }); @@ -175,7 +179,7 @@ describe("", () => { labels: { alertname: "Fake Alert", groupName: "fakeGroup" }, }), ); - tree.unmount(); + unmount(); }); it("send a correct payload with shared labels", async () => { @@ -196,7 +200,9 @@ describe("", () => { { name: "shared1", value: "value1" }, { name: "shared2", value: "value2" }, ]); - const tree = mount(); + const { unmount } = render( + , + ); await act(async () => { await fetchMock.flush(true); }); @@ -216,7 +222,7 @@ describe("", () => { }, }), ); - tree.unmount(); + unmount(); }); it("matches snapshot with empty response", async () => { @@ -233,13 +239,15 @@ describe("", () => { ); MockAlerts(3); - const tree = mount(); + const { unmount, asFragment } = render( + , + ); await act(async () => { await fetchMock.flush(true); }); expect(fetchMock.calls()).toHaveLength(1); - expect(toDiffableHtml(tree.html())).toMatchSnapshot(); - tree.unmount(); + expect(asFragment()).toMatchSnapshot(); + unmount(); }); it("matches snapshot with rainbow response", async () => { @@ -256,13 +264,15 @@ describe("", () => { ); MockAlerts(3); - const tree = mount(); + const { unmount, asFragment } = render( + , + ); await act(async () => { await fetchMock.flush(true); }); expect(fetchMock.calls()).toHaveLength(1); - expect(toDiffableHtml(tree.html())).toMatchSnapshot(); - tree.unmount(); + expect(asFragment()).toMatchSnapshot(); + unmount(); }); it("doesn't fetch when not in view", async () => { @@ -284,11 +294,13 @@ describe("", () => { ] as any); MockAlerts(3); - const tree = mount(); + const { unmount } = render( + , + ); await act(async () => { await fetchMock.flush(true); }); - tree.unmount(); + unmount(); expect(fetchMock.calls()).toHaveLength(0); }); @@ -313,7 +325,9 @@ describe("", () => { ] as any); MockAlerts(3); - const tree = mount(); + const { unmount } = render( + , + ); await act(async () => { await fetchMock.flush(true); }); @@ -331,7 +345,7 @@ describe("", () => { }); expect(fetchMock.calls()).toHaveLength(2); - tree.unmount(); + unmount(); }); it("handles reponses with errors", async () => { @@ -348,13 +362,15 @@ describe("", () => { ); MockAlerts(3); - const tree = mount(); + const { unmount, asFragment } = render( + , + ); await act(async () => { await fetchMock.flush(true); }); expect(fetchMock.calls()).toHaveLength(1); - expect(toDiffableHtml(tree.html())).toMatchSnapshot(); - tree.unmount(); + expect(asFragment()).toMatchSnapshot(); + unmount(); }); it("handles fetch errors", async () => { @@ -371,13 +387,15 @@ describe("", () => { ); MockAlerts(3); - const tree = mount(); + const { unmount, asFragment } = render( + , + ); await act(async () => { await fetchMock.flush(true); }); expect(fetchMock.calls()).toHaveLength(1); - expect(toDiffableHtml(tree.html())).toMatchSnapshot(); - tree.unmount(); + expect(asFragment()).toMatchSnapshot(); + unmount(); }); interface testCasesT { @@ -518,15 +536,18 @@ describe("", () => { }, ); - const tree = mount(); + const { container, unmount } = render( + , + ); await act(async () => { await fetchMock.flush(true); }); - tree.update(); - const rects = tree.find("rect").map((r) => r.props().className); + const rects = Array.from(container.querySelectorAll("rect")).map( + (r) => r.className.baseVal, + ); expect(rects).toStrictEqual(testCase.values); - tree.unmount(); + unmount(); }); } }); diff --git a/ui/src/Components/CenteredMessage/__snapshots__/index.test.tsx.snap b/ui/src/Components/CenteredMessage/__snapshots__/index.test.tsx.snap index 7c0dba7df..9f2c0f324 100644 --- a/ui/src/Components/CenteredMessage/__snapshots__/index.test.tsx.snap +++ b/ui/src/Components/CenteredMessage/__snapshots__/index.test.tsx.snap @@ -1,11 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` matches snapshot 1`] = ` -" -

-
- Foo -
-

-" + +

+
+ Foo +
+

+
`; diff --git a/ui/src/Components/CenteredMessage/index.test.tsx b/ui/src/Components/CenteredMessage/index.test.tsx index 49ee2a056..8e279798a 100644 --- a/ui/src/Components/CenteredMessage/index.test.tsx +++ b/ui/src/Components/CenteredMessage/index.test.tsx @@ -1,46 +1,48 @@ -import React from "react"; - -import { shallow } from "enzyme"; - -import toDiffableHtml from "diffable-html"; +import { render, screen } from "@testing-library/react"; import { MockThemeContext } from "__fixtures__/Theme"; +import { ThemeContext } from "Components/Theme"; import { CenteredMessage } from "."; -beforeEach(() => { - jest.spyOn(React, "useContext").mockImplementation(() => MockThemeContext); -}); +const renderWithTheme = (ui: React.ReactElement) => + render( + + {ui} + , + ); describe("", () => { const Message = () =>
Foo
; it("matches snapshot", () => { - const tree = shallow( + const { asFragment } = renderWithTheme( , ); - expect(toDiffableHtml(tree.html())).toMatchSnapshot(); + expect(asFragment()).toMatchSnapshot(); }); it("uses 'display-1 text-placeholder' className by default", () => { - const tree = shallow( + renderWithTheme( , ); - expect(toDiffableHtml(tree.html())).toMatch(/display-1 text-placeholder/); + expect(screen.getByRole("heading")).toHaveClass( + "display-1", + "text-placeholder", + ); }); it("uses custom className if passed", () => { - const tree = shallow( + renderWithTheme( , ); - expect(toDiffableHtml(tree.html())).toMatch(/bar-class/); - expect(toDiffableHtml(tree.html())).not.toMatch( - /display-1 text-placeholder/, - ); + const heading = screen.getByRole("heading"); + expect(heading).toHaveClass("bar-class"); + expect(heading).not.toHaveClass("display-1", "text-placeholder"); }); }); diff --git a/ui/src/Components/DateFromNow/index.test.tsx b/ui/src/Components/DateFromNow/index.test.tsx index 8c2b3a8eb..9e4c0e924 100644 --- a/ui/src/Components/DateFromNow/index.test.tsx +++ b/ui/src/Components/DateFromNow/index.test.tsx @@ -1,4 +1,4 @@ -import { mount } from "enzyme"; +import { render, screen } from "@testing-library/react"; import { addSeconds } from "date-fns/addSeconds"; import { subSeconds } from "date-fns/subSeconds"; @@ -7,35 +7,35 @@ import { DateFromNow } from "."; describe("", () => { it("renders 'just now' for now", () => { - const tree = mount(); - expect(tree.text()).toBe("just now"); + render(); + expect(screen.getByText("just now")).toBeInTheDocument(); }); it("renders 'a few seconds ago' for 35 seconds old timestamp", () => { - const tree = mount( + render( , ); - expect(tree.text()).toBe("a few seconds ago"); + expect(screen.getByText("a few seconds ago")).toBeInTheDocument(); }); it("renders 'in a few seconds' for a timestamp 35 seconds away", () => { - const tree = mount( + render( , ); - expect(tree.text()).toBe("in a few seconds"); + expect(screen.getByText("in a few seconds")).toBeInTheDocument(); }); it("renders '1 minute ago' for 65 seconds old timestamp", () => { - const tree = mount( + render( , ); - expect(tree.text()).toBe("1 minute ago"); + expect(screen.getByText("1 minute ago")).toBeInTheDocument(); }); it("renders 'in 1 minute' for a timestamp 65 seconds away", () => { - const tree = mount( + render( , ); - expect(tree.text()).toBe("in 1 minute"); + expect(screen.getByText("in 1 minute")).toBeInTheDocument(); }); }); diff --git a/ui/src/Components/FaviconBadge/index.test.tsx b/ui/src/Components/FaviconBadge/index.test.tsx index aae0f6ddd..16ce0a3f5 100644 --- a/ui/src/Components/FaviconBadge/index.test.tsx +++ b/ui/src/Components/FaviconBadge/index.test.tsx @@ -1,4 +1,4 @@ -import { mount } from "enzyme"; +import { render } from "@testing-library/react"; import Favico from "favico.js"; @@ -12,21 +12,21 @@ beforeEach(() => { Favico.badge.mockClear(); }); -const MountedFaviconBadge = () => { - return mount(); +const renderFaviconBadge = () => { + return render(); }; describe("", () => { it("badge is updated on mount", () => { alertStore.info.setTotalAlerts(99); - MountedFaviconBadge(); + renderFaviconBadge(); expect(Favico.badge).toHaveBeenCalledTimes(1); expect(Favico.badge).toHaveBeenCalledWith(99); }); it("badge is updated when alertStore.info.totalAlerts changes", () => { alertStore.info.setTotalAlerts(99); - MountedFaviconBadge(); + renderFaviconBadge(); expect(Favico.badge).toHaveBeenCalledTimes(1); expect(Favico.badge).toHaveBeenCalledWith(99); @@ -37,7 +37,7 @@ describe("", () => { it("badge is updated when alertStore.status.error changes", () => { alertStore.status.setError("foo"); - MountedFaviconBadge(); + renderFaviconBadge(); expect(Favico.badge).toHaveBeenCalledTimes(1); expect(Favico.badge).toHaveBeenCalledWith("?"); }); @@ -61,7 +61,7 @@ describe("", () => { }, ], }); - MountedFaviconBadge(); + renderFaviconBadge(); expect(Favico.badge).toHaveBeenCalledWith("!"); }); }); diff --git a/ui/src/Components/FetchPauser/index.test.tsx b/ui/src/Components/FetchPauser/index.test.tsx index 64fc09a07..dfca7a9f2 100644 --- a/ui/src/Components/FetchPauser/index.test.tsx +++ b/ui/src/Components/FetchPauser/index.test.tsx @@ -1,6 +1,6 @@ import { act } from "react-dom/test-utils"; -import { mount } from "enzyme"; +import { render } from "@testing-library/react"; import { AlertStore } from "Stores/AlertStore"; import { FetchPauser } from "."; @@ -11,8 +11,8 @@ beforeEach(() => { alertStore = new AlertStore([]); }); -const MountedFetchPauser = () => { - return mount( +const renderFetchPauser = () => { + return render(
, @@ -21,14 +21,14 @@ const MountedFetchPauser = () => { describe("", () => { it("mounting FetchPauser pauses alertStore", () => { - MountedFetchPauser(); + renderFetchPauser(); expect(alertStore.status.paused).toBe(true); }); it("unmounting FetchPauser resumes alertStore", () => { - const tree = MountedFetchPauser(); + const { unmount } = renderFetchPauser(); act(() => { - tree.unmount(); + unmount(); }); expect(alertStore.status.paused).toBe(false); }); diff --git a/ui/src/Components/Fetcher/__snapshots__/index.test.tsx.snap b/ui/src/Components/Fetcher/__snapshots__/index.test.tsx.snap index 0492ddb6e..ea0996a3b 100644 --- a/ui/src/Components/Fetcher/__snapshots__/index.test.tsx.snap +++ b/ui/src/Components/Fetcher/__snapshots__/index.test.tsx.snap @@ -1,26 +1,37 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` matches snapshot 1`] = ` -" -
-
+ +
+
+
+
+
+
+
+
+
+ -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-" + `; diff --git a/ui/src/Components/Fetcher/index.test.tsx b/ui/src/Components/Fetcher/index.test.tsx index 0b6df5d7c..7cf9888ee 100644 --- a/ui/src/Components/Fetcher/index.test.tsx +++ b/ui/src/Components/Fetcher/index.test.tsx @@ -1,11 +1,9 @@ import { act } from "react-dom/test-utils"; -import { mount } from "enzyme"; +import { render, fireEvent } from "@testing-library/react"; import fetchMock from "fetch-mock"; -import toDiffableHtml from "diffable-html"; - import { EmptyAPIResponse } from "__fixtures__/Fetch"; import { AlertStore } from "Stores/AlertStore"; @@ -66,7 +64,7 @@ const MockEmptyAPIResponseWithoutFilters = () => { describe("", () => { it("changing interval changes how often fetch is called", () => { settingsStore.fetchConfig.setInterval(1); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledTimes(1); jest.setSystemTime( @@ -114,23 +112,23 @@ describe("", () => { it("calls alertStore.fetchWithThrottle on mount", () => { const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle"); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledTimes(1); }); it("calls alertStore.fetchWithThrottle again after filter change", () => { MockEmptyAPIResponseWithoutFilters(); const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle"); - const tree = mount( + const { rerender } = render( , ); alertStore.filters.setFilterValues([]); - tree.setProps({}); + rerender(); expect(fetchSpy).toHaveBeenCalledTimes(2); }); it("keeps calling alertStore.fetchWithThrottle every minute", () => { - mount(); + render(); expect(fetchSpy).toHaveBeenCalledTimes(1); jest.setSystemTime( @@ -162,7 +160,7 @@ describe("", () => { MockEmptyAPIResponseWithoutFilters(); const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle"); settingsStore.gridConfig.setSortOrder("default"); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith("", false, "", "", false, {}, 5, {}); }); @@ -171,7 +169,7 @@ describe("", () => { const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle"); settingsStore.gridConfig.setSortOrder("disabled"); settingsStore.gridConfig.setSortReverse(false); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith( "", false, @@ -189,7 +187,7 @@ describe("", () => { const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle"); settingsStore.gridConfig.setSortOrder("disabled"); settingsStore.gridConfig.setSortReverse(true); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith( "", false, @@ -207,7 +205,7 @@ describe("", () => { const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle"); settingsStore.gridConfig.setSortOrder("startsAt"); settingsStore.gridConfig.setSortReverse(false); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith( "", false, @@ -225,7 +223,7 @@ describe("", () => { const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle"); settingsStore.gridConfig.setSortOrder("startsAt"); settingsStore.gridConfig.setSortReverse(true); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith( "", false, @@ -244,7 +242,7 @@ describe("", () => { settingsStore.gridConfig.setSortOrder("label"); settingsStore.gridConfig.setSortLabel("cluster"); settingsStore.gridConfig.setSortReverse(false); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith( "", false, @@ -263,7 +261,7 @@ describe("", () => { settingsStore.gridConfig.setSortOrder("label"); settingsStore.gridConfig.setSortLabel("job"); settingsStore.gridConfig.setSortReverse(true); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith( "", false, @@ -282,7 +280,7 @@ describe("", () => { settingsStore.gridConfig.setSortOrder("label"); settingsStore.gridConfig.setSortLabel("instance"); settingsStore.gridConfig.setSortReverse(null); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith( "", false, @@ -301,7 +299,7 @@ describe("", () => { settingsStore.gridConfig.setSortOrder("default"); settingsStore.multiGridConfig.setGridLabel("cluster"); settingsStore.multiGridConfig.setGridSortReverse(false); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith( "cluster", false, @@ -320,7 +318,7 @@ describe("", () => { settingsStore.gridConfig.setSortOrder("default"); settingsStore.multiGridConfig.setGridLabel("cluster"); settingsStore.multiGridConfig.setGridSortReverse(true); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith( "cluster", true, @@ -339,7 +337,7 @@ describe("", () => { settingsStore.gridConfig.setSortOrder("default"); settingsStore.multiGridConfig.setGridLabel(""); settingsStore.multiGridConfig.setGridSortReverse(true); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith("", true, "", "", false, {}, 5, {}); }); @@ -351,7 +349,7 @@ describe("", () => { settingsStore.multiGridConfig.setGridSortReverse(false); alertStore.ui.setGridGroupLimit("old", "bar", 10); alertStore.ui.setGridGroupLimit("foo", "bar", 5); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledWith( "", false, @@ -365,13 +363,13 @@ describe("", () => { }); it("internal timer is null after unmount", () => { - const tree = mount( + const { unmount } = render( , ); expect(fetchSpy).toHaveBeenCalledTimes(1); act(() => { - tree.unmount(); + unmount(); }); expect(fetchSpy).toHaveBeenCalledTimes(1); @@ -389,13 +387,13 @@ describe("", () => { it("doesn't fetch on mount when paused", () => { alertStore.status.pause(); - mount(); + render(); expect(fetchSpy).toHaveBeenCalledTimes(0); }); it("doesn't fetch on update when paused", () => { alertStore.status.pause(); - mount(); + render(); settingsStore.gridConfig.setSortReverse( !settingsStore.gridConfig.config.reverseSort, ); @@ -404,7 +402,7 @@ describe("", () => { it("fetches on update when resumed", () => { alertStore.status.pause(); - mount(); + render(); alertStore.status.resume(); settingsStore.gridConfig.setSortReverse( !settingsStore.gridConfig.config.reverseSort, @@ -417,7 +415,7 @@ describe("", () => { it("fetches on resume", () => { alertStore.status.pause(); - mount(); + render(); alertStore.status.resume(); jest.setSystemTime( new Date(Date.UTC(2000, 1, 1, 0, 0, 0)).getTime() + 2 * 1000, @@ -431,91 +429,105 @@ describe("", () => { describe(" children", () => { it("renders Dots when countdown is in progress", () => { - const tree = mount( + const { container } = render( , ); - expect(tree.find("div.components-fetcher")).toHaveLength(1); + expect(container.querySelectorAll("div.components-fetcher")).toHaveLength( + 1, + ); }); it("doesn't render any children when upgrade is needed", () => { act(() => { alertStore.info.setUpgradeNeeded(true); }); - const tree = mount( + const { container } = render( , ); - expect(tree.find("div.navbar-brand").children()).toHaveLength(0); + expect(container.querySelector("div.navbar-brand")?.children).toHaveLength( + 0, + ); }); it("renders PauseButton when paused", () => { - const tree = mount( + const { container } = render( , ); act(() => { alertStore.status.pause(); }); - expect(toDiffableHtml(tree.html())).toMatch(/fa-pause/); + expect(container.innerHTML).toMatch(/fa-pause/); }); it("renders PauseButton when paused and hovered", () => { - const tree = mount( + const { container } = render( , ); act(() => { alertStore.status.pause(); }); - tree.find(".navbar-brand").simulate("mouseenter"); - tree.update(); - expect(toDiffableHtml(tree.html())).toMatch(/fa-pause/); + const navbarBrand = container.querySelector(".navbar-brand"); + fireEvent.mouseEnter(navbarBrand!); + expect(container.innerHTML).toMatch(/fa-pause/); - tree.find(".navbar-brand").simulate("mouseleave"); - tree.update(); - expect(toDiffableHtml(tree.html())).toMatch(/fa-pause/); + fireEvent.mouseLeave(navbarBrand!); + expect(container.innerHTML).toMatch(/fa-pause/); }); it("renders PlayButton when hovered", () => { - const tree = mount( + const { container } = render( , ); - tree.find(".navbar-brand").simulate("mouseenter"); - tree.update(); - expect(toDiffableHtml(tree.html())).toMatch(/fa-play/); + const navbarBrand = container.querySelector(".navbar-brand"); + fireEvent.mouseEnter(navbarBrand!); + expect(container.innerHTML).toMatch(/fa-play/); - tree.find(".navbar-brand").simulate("mouseleave"); - tree.update(); - expect(tree.find("div.components-fetcher")).toHaveLength(1); + fireEvent.mouseLeave(navbarBrand!); + expect(container.querySelectorAll("div.components-fetcher")).toHaveLength( + 1, + ); }); }); describe("", () => { it("matches snapshot", () => { - const tree = mount(); - expect(toDiffableHtml(tree.html())).toMatchSnapshot(); + const { asFragment } = render(); + expect(asFragment()).toMatchSnapshot(); }); it("adds 'fetching' class when fetching data", () => { act(() => { alertStore.status.setFetching(); }); - const tree = mount(); - expect(tree.find("div.components-fetcher").hasClass("fetching")).toBe(true); + const { container } = render(); + expect( + container + .querySelector("div.components-fetcher") + ?.classList.contains("fetching"), + ).toBe(true); }); it("adds 'processing' class when processing fetched data", () => { act(() => { alertStore.status.setProcessing(); }); - const tree = mount(); - expect(tree.find("div.components-fetcher").hasClass("processing")).toBe( - true, - ); + const { container } = render(); + expect( + container + .querySelector("div.components-fetcher") + ?.classList.contains("processing"), + ).toBe(true); }); it("adds 'retrying' class when fetch needs a retry", () => { act(() => { alertStore.info.setIsRetrying(); }); - const tree = mount(); - expect(tree.find("div.components-fetcher").hasClass("retrying")).toBe(true); + const { container } = render(); + expect( + container + .querySelector("div.components-fetcher") + ?.classList.contains("retrying"), + ).toBe(true); }); }); diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.test.tsx b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.test.tsx index d43486e10..57e2bba2c 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.test.tsx +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.test.tsx @@ -1,6 +1,6 @@ import { act } from "react-dom/test-utils"; -import { mount } from "enzyme"; +import { render, fireEvent } from "@testing-library/react"; import copy from "copy-to-clipboard"; @@ -100,8 +100,8 @@ beforeEach(() => { alertStore.data.setUpstreams(generateUpstreams()); }); -const MountedAlertMenu = (group: APIAlertGroupT) => { - return mount( +const renderAlertMenu = (group: APIAlertGroupT) => { + return render( { describe("", () => { it("menu content is hidden by default", () => { - const tree = MountedAlertMenu(group); - expect(tree.find("div.dropdown-menu")).toHaveLength(0); + const { container } = renderAlertMenu(group); + expect(container.querySelector("div.dropdown-menu")).toBeNull(); expect(MockSetIsMenuOpen).not.toHaveBeenCalled(); }); it("clicking toggle renders menu content", async () => { const promise = Promise.resolve(); - const tree = MountedAlertMenu(group); - const toggle = tree.find("span.cursor-pointer"); - toggle.simulate("click"); + const { container } = renderAlertMenu(group); + const toggle = container.querySelector("span.cursor-pointer"); + fireEvent.click(toggle!); expect(MockSetIsMenuOpen).toHaveBeenCalledTimes(1); - expect(tree.find("div.dropdown-menu")).toHaveLength(1); + expect(container.querySelector("div.dropdown-menu")).toBeInTheDocument(); await act(() => promise); }); it("clicking toggle twice hides menu content", async () => { const promise = Promise.resolve(); - const tree = MountedAlertMenu(group); - const toggle = tree.find("span.cursor-pointer"); + const { container } = renderAlertMenu(group); + const toggle = container.querySelector("span.cursor-pointer"); - toggle.simulate("click"); + fireEvent.click(toggle!); act(() => { jest.runOnlyPendingTimers(); }); expect(MockSetIsMenuOpen).toHaveBeenCalledTimes(1); - expect(tree.find("div.dropdown-menu")).toHaveLength(1); + expect(container.querySelector("div.dropdown-menu")).toBeInTheDocument(); - toggle.simulate("click"); + fireEvent.click(toggle!); act(() => { jest.runOnlyPendingTimers(); }); - tree.update(); expect(MockSetIsMenuOpen).toHaveBeenCalledTimes(2); - expect(tree.find("div.dropdown-menu")).toHaveLength(0); + expect(container.querySelector("div.dropdown-menu")).toBeNull(); await act(() => promise); }); it("clicking menu item hides menu content", async () => { const promise = Promise.resolve(); - const tree = MountedAlertMenu(group); - const toggle = tree.find("span.cursor-pointer"); + const { container } = renderAlertMenu(group); + const toggle = container.querySelector("span.cursor-pointer"); - toggle.simulate("click"); + fireEvent.click(toggle!); expect(MockSetIsMenuOpen).toHaveBeenCalledTimes(1); - expect(tree.find("div.dropdown-menu")).toHaveLength(1); + expect(container.querySelector("div.dropdown-menu")).toBeInTheDocument(); - tree.find("a.dropdown-item").at(0).simulate("click"); + const menuItem = container.querySelector("a.dropdown-item"); + fireEvent.click(menuItem!); act(() => { jest.runOnlyPendingTimers(); }); - tree.update(); expect(MockSetIsMenuOpen).toHaveBeenCalledTimes(2); - expect(tree.find("div.dropdown-menu")).toHaveLength(0); + expect(container.querySelector("div.dropdown-menu")).toBeNull(); await act(() => promise); }); }); -const MountedMenuContent = (group: APIAlertGroupT) => { - return mount( +const renderMenuContent = (group: APIAlertGroupT) => { + return render( { describe("", () => { it("clicking on 'Silence' icon opens the silence form modal", () => { group.alertmanagerCount = { am1: 1, ro: 1 }; - const tree = MountedMenuContent(group); - const button = tree.find(".dropdown-item").at(2); - button.simulate("click"); + const { container } = renderMenuContent(group); + const buttons = container.querySelectorAll(".dropdown-item"); + fireEvent.click(buttons[2]); expect(silenceFormStore.toggle.visible).toBe(true); expect(silenceFormStore.data.alertmanagers).toMatchObject([ { label: "am1", value: ["am1"] }, @@ -205,17 +204,19 @@ describe("", () => { upstreams.instances[0].readonly = true; upstreams.instances[2].readonly = true; alertStore.data.setUpstreams(upstreams); - const tree = MountedMenuContent(group); - const button = tree.find(".dropdown-item").at(2); - expect(button.hasClass("disabled")).toBe(true); - button.simulate("click"); + const { container } = renderMenuContent(group); + const buttons = container.querySelectorAll(".dropdown-item"); + expect(buttons[2].classList.contains("disabled")).toBe(true); + fireEvent.click(buttons[2]); expect(silenceFormStore.toggle.visible).toBe(false); }); it("source link points at alert source", () => { - const tree = MountedMenuContent(group); - const link = tree.find("a.dropdown-item[href='localhost/graph']"); - expect(link.text()).toBe("default"); + const { container } = renderMenuContent(group); + const link = container.querySelector( + "a.dropdown-item[href='localhost/graph']", + ); + expect(link?.textContent).toBe("default"); }); it("renders action annotations when present", () => { @@ -276,34 +277,30 @@ describe("", () => { {}, ); - const tree = MountedMenuContent(group); - expect(tree.find("a.dropdown-item")).toHaveLength(3); + const { container } = renderMenuContent(group); + expect(container.querySelectorAll("a.dropdown-item")).toHaveLength(3); - const link1 = tree.find("a.dropdown-item[href='linkAction']"); - expect(link1.text()).toBe("linkAction"); + const link1 = container.querySelector("a.dropdown-item[href='linkAction']"); + expect(link1?.textContent).toBe("linkAction"); - const link2 = tree.find("a.dropdown-item[href='linkActionShared']"); - expect(link2.text()).toBe("linkActionShared"); - - expect(tree.find("a.dropdown-item[href='nonLinkNonAction']")).toHaveLength( - 0, - ); - expect(tree.find("a.dropdown-item[href='nonLinkNonAction']")).toHaveLength( - 0, + const link2 = container.querySelector( + "a.dropdown-item[href='linkActionShared']", ); + expect(link2?.textContent).toBe("linkActionShared"); + expect( - tree.find("a.dropdown-item[href='nonLinkNonActionShared']"), - ).toHaveLength(0); + container.querySelector("a.dropdown-item[href='nonLinkNonAction']"), + ).toBeNull(); expect( - tree.find("a.dropdown-item[href='nonLinkNonActionShared']"), - ).toHaveLength(0); + container.querySelector("a.dropdown-item[href='nonLinkNonActionShared']"), + ).toBeNull(); }); it("clicking on 'Copy' icon copies alert data to clipboard", async () => { group.alertmanagerCount = { am1: 1, ro: 1 }; - const tree = MountedMenuContent(group); - const button = tree.find(".dropdown-item").at(1); - button.simulate("click"); + const { container } = renderMenuContent(group); + const buttons = container.querySelectorAll(".dropdown-item"); + fireEvent.click(buttons[1]); expect(copy).toBeCalledWith(JSON.stringify(alertToJSON(group, alert))); }); }); diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/__snapshots__/index.test.tsx.snap b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/__snapshots__/index.test.tsx.snap index d19433a9c..b304fc65f 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/__snapshots__/index.test.tsx.snap +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/__snapshots__/index.test.tsx.snap @@ -1,261 +1,324 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` matches snapshot when inhibited 1`] = ` -" -
  • -
    -
    -
    - + +
  • +
    +
    +
    + + + + help: + + + + + some long text + + +
    +
    +
    +
    - - help: - - - - - some long text - - + hidden +
    -
    -
    + + - hidden -
    + 1 day ago + + +
    + + +
    -
    - - + + + job: + + + + node_exporter + + +
  • +
    + + + cluster: + + + + dev + + +
    + - 1 day ago - - -
    - - - -
    -
    - - - job: - - - node_exporter - - -
    -
    - - - cluster: - - - dev - - -
    -
    - - link - - -" + link + + + `; exports[` matches snapshot with showAlertmanagers=false showReceiver=false 1`] = ` -" -
  • -
    -
    -
    - + +
  • +
    +
    +
    + + + + help: + + + + + some long text + + +
    +
    +
    +
    - - help: - - - - - some long text - - + hidden +
    -
    -
    + + - hidden -
    + 1 day ago + + +
    + + + job: + + + + node_exporter + +
    -
    - - + + + cluster: + + + + dev + + +
  • + - 1 day ago - - -
    - - - job: - - - node_exporter - - -
    -
    - - - cluster: - - - dev - - -
    -
    - - link - - -" + link + + + `; diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.test.tsx b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.test.tsx index e1d435c79..667264712 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.test.tsx +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.test.tsx @@ -1,8 +1,6 @@ import { act } from "react-dom/test-utils"; -import { mount } from "enzyme"; - -import toDiffableHtml from "diffable-html"; +import { render } from "@testing-library/react"; import { MockAlert, @@ -64,28 +62,26 @@ const MockedAlert = () => { ); }; -const MountedAlert = ( +const renderAlert = ( alert: APIAlertT, group: APIAlertGroupT, showReceiver: boolean, showOnlyExpandedAnnotations: boolean, ) => { - return mount( - , - { - wrappingComponent: ThemeContext.Provider, - wrappingComponentProps: { value: MockThemeContext }, - }, + return render( + + + , ); }; @@ -94,8 +90,8 @@ describe("", () => { const alert = MockedAlert(); const group = MockAlertGroup([], [alert], [], [], {}); group.shared.clusters = ["default"]; - const tree = MountedAlert(alert, group, false, false); - expect(toDiffableHtml(tree.html())).toMatchSnapshot(); + const { asFragment } = renderAlert(alert, group, false, false); + expect(asFragment()).toMatchSnapshot(); }); it("matches snapshot when inhibited", () => { @@ -103,8 +99,8 @@ describe("", () => { alert.alertmanager[0].inhibitedBy = ["123456"]; const group = MockAlertGroup([], [alert], [], [], {}); group.shared.clusters = ["default"]; - const tree = MountedAlert(alert, group, false, false); - expect(toDiffableHtml(tree.html())).toMatchSnapshot(); + const { asFragment } = renderAlert(alert, group, false, false); + expect(asFragment()).toMatchSnapshot(); }); it("renders inhibition icon when inhibited", () => { @@ -121,16 +117,16 @@ describe("", () => { inhibitedBy: ["123456"], }); const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, false); - expect(tree.find(".fa-volume-xmark")).toHaveLength(1); + const { container } = renderAlert(alert, group, false, false); + expect(container.querySelectorAll(".fa-volume-xmark")).toHaveLength(1); }); it("inhibition icon passes only unique fingerprints", () => { const alert = MockedAlert(); alert.alertmanager[0].inhibitedBy = ["123456"]; const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, false); - expect(tree.find(".fa-volume-xmark")).toHaveLength(1); + const { container } = renderAlert(alert, group, false, false); + expect(container.querySelectorAll(".fa-volume-xmark")).toHaveLength(1); }); it("renders @cluster label for non-shared clusters", () => { @@ -167,11 +163,8 @@ describe("", () => { const alert = MockedAlert(); const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, false); - const label = tree - .find("Memo(FilteringLabel)") - .filterWhere((elem) => elem.props().name === "@cluster"); - expect(label.text()).toBe("@cluster: default"); + const { container } = renderAlert(alert, group, false, false); + expect(container.textContent).toMatch(/@cluster:.*default/); }); it("only renders one @cluster label per alertmanager cluster", () => { @@ -227,23 +220,16 @@ describe("", () => { inhibitedBy: [], }); const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, false); - const labels = tree - .find("Memo(FilteringLabel)") - .filterWhere((elem) => elem.props().name === "@cluster"); - expect(labels).toHaveLength(2); - expect(labels.at(0).text()).toBe("@cluster: default"); - expect(labels.at(1).text()).toBe("@cluster: HA"); + const { container } = renderAlert(alert, group, false, false); + expect(container.textContent).toMatch(/@cluster:.*default/); + expect(container.textContent).toMatch(/@cluster:.*HA/); }); it("renders @receiver label with showReceiver=true", () => { const alert = MockedAlert(); const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, true, false); - const label = tree - .find("Memo(FilteringLabel)") - .filterWhere((elem) => elem.props().name === "@receiver"); - expect(label.text()).toBe("@receiver: by-name"); + const { container } = renderAlert(alert, group, true, false); + expect(container.textContent).toMatch(/@receiver:.*by-name/); }); it("renders a silence if alert is silenced", () => { @@ -255,10 +241,8 @@ describe("", () => { }, }); const group = MockAlertGroup([], [alert], [], [], { default: [] }); - const tree = MountedAlert(alert, group, false, false); - const silence = tree.find("ManagedSilence"); - expect(silence).toHaveLength(1); - expect(silence.html()).toMatch(/Mocked Silence/); + const { container } = renderAlert(alert, group, false, false); + expect(container.innerHTML).toMatch(/Mocked Silence/); }); it("renders a fallback silence if the silence is not found in alertStore", () => { @@ -270,10 +254,9 @@ describe("", () => { }, }); const group = MockAlertGroup([], [alert], [], [], { default: [] }); - const tree = MountedAlert(alert, group, false, false); - const silence = tree.find("FallbackSilenceDesciption"); - expect(silence).toHaveLength(1); - expect(silence.html()).not.toMatch(/Mocked Silence/); + const { container } = renderAlert(alert, group, false, false); + expect(container.innerHTML).not.toMatch(/Mocked Silence/); + expect(container.innerHTML).toMatch(/silence123456789/); }); it("renders a fallback silence if the cluster is not found in alertStore", () => { @@ -285,10 +268,9 @@ describe("", () => { }, }); const group = MockAlertGroup([], [alert], [], [], { default: [] }); - const tree = MountedAlert(alert, group, false, false); - const silence = tree.find("FallbackSilenceDesciption"); - expect(silence).toHaveLength(1); - expect(silence.html()).not.toMatch(/Mocked Silence/); + const { container } = renderAlert(alert, group, false, false); + expect(container.innerHTML).not.toMatch(/Mocked Silence/); + expect(container.innerHTML).toMatch(/silence123456789/); }); it("renders only one silence for HA cluster", () => { @@ -321,10 +303,8 @@ describe("", () => { }, }); const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, false); - const silence = tree.find("ManagedSilence"); - expect(silence).toHaveLength(1); - expect(silence.html()).toMatch(/Mocked Silence/); + const { container } = renderAlert(alert, group, false, false); + expect(container.innerHTML).toMatch(/Mocked Silence/); }); it("doesn't render shared silences", () => { @@ -333,9 +313,8 @@ describe("", () => { const group = MockAlertGroup([], [alert], [], [], { default: ["silence123456789"], }); - const tree = MountedAlert(alert, group, false, false); - const silence = tree.find("ManagedSilence"); - expect(silence).toHaveLength(0); + const { container } = renderAlert(alert, group, false, false); + expect(container.innerHTML).not.toMatch(/Mocked Silence/); }); it("renders collapsed annotations when showOnlyExpandedAnnotations=false", () => { @@ -357,8 +336,10 @@ describe("", () => { }, ]; const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, false); - const annotations = tree.find("div.components-grid-annotation"); + const { container } = renderAlert(alert, group, false, false); + const annotations = container.querySelectorAll( + "div.components-grid-annotation", + ); expect(annotations).toHaveLength(2); }); @@ -381,8 +362,10 @@ describe("", () => { }, ]; const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, true); - const annotations = tree.find("div.components-grid-annotation"); + const { container } = renderAlert(alert, group, false, true); + const annotations = container.querySelectorAll( + "div.components-grid-annotation", + ); expect(annotations).toHaveLength(1); }); @@ -390,36 +373,33 @@ describe("", () => { const alert = MockedAlert(); alert.state = "active"; const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, false); - expect( - tree - .find(".components-grid-alertgrid-alertgroup-alert") - .hasClass(BorderClassMap.active), - ).toBe(true); + const { container } = renderAlert(alert, group, false, false); + const alertEl = container.querySelector( + ".components-grid-alertgrid-alertgroup-alert", + ); + expect(alertEl?.classList.contains(BorderClassMap.active)).toBe(true); }); it("uses BorderClassMap.suppressed when @state=suppressed", () => { const alert = MockedAlert(); alert.state = "suppressed"; const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, false); - expect( - tree - .find(".components-grid-alertgrid-alertgroup-alert") - .hasClass(BorderClassMap.suppressed), - ).toBe(true); + const { container } = renderAlert(alert, group, false, false); + const alertEl = container.querySelector( + ".components-grid-alertgrid-alertgroup-alert", + ); + expect(alertEl?.classList.contains(BorderClassMap.suppressed)).toBe(true); }); it("uses BorderClassMap.unprocessed when @state=unprocessed", () => { const alert = MockedAlert(); alert.state = "unprocessed"; const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, false); - expect( - tree - .find(".components-grid-alertgrid-alertgroup-alert") - .hasClass(BorderClassMap.unprocessed), - ).toBe(true); + const { container } = renderAlert(alert, group, false, false); + const alertEl = container.querySelector( + ".components-grid-alertgrid-alertgroup-alert", + ); + expect(alertEl?.classList.contains(BorderClassMap.unprocessed)).toBe(true); }); it("uses 'border-default' with unknown @state", () => { @@ -428,12 +408,11 @@ describe("", () => { const alert = MockedAlert(); (alert.state as string) = "foobar"; const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, false); - expect( - tree - .find(".components-grid-alertgrid-alertgroup-alert") - .hasClass("border-default"), - ).toBe(true); + const { container } = renderAlert(alert, group, false, false); + const alertEl = container.querySelector( + ".components-grid-alertgrid-alertgroup-alert", + ); + expect(alertEl?.classList.contains("border-default")).toBe(true); }); it("alert timestamp is updated every minute", () => { @@ -443,67 +422,41 @@ describe("", () => { const alert = MockedAlert(); const group = MockAlertGroup([], [alert], [], [], {}); - const tree = MountedAlert(alert, group, false, false); - expect( - tree - .find("span.components-label.badge.bg-secondary.cursor-pointer") - .at(0) - .text(), - ).toBe("just now"); + const { container } = renderAlert(alert, group, false, false); + const getTimestamp = () => + container.querySelector( + "span.components-label.badge.bg-secondary.cursor-pointer", + )?.textContent; + expect(getTimestamp()).toBe("just now"); jest.setSystemTime(new Date(Date.UTC(2018, 7, 14, 17, 36, 42))); act(() => { jest.advanceTimersByTime(31 * 1000); }); - expect( - tree - .find("span.components-label.badge.bg-secondary.cursor-pointer") - .at(0) - .text(), - ).toBe("a few seconds ago"); + expect(getTimestamp()).toBe("a few seconds ago"); jest.setSystemTime(new Date(Date.UTC(2018, 7, 14, 17, 37, 41))); act(() => { jest.advanceTimersByTime(31 * 1000); }); - expect( - tree - .find("span.components-label.badge.bg-secondary.cursor-pointer") - .at(0) - .text(), - ).toBe("1 minute ago"); + expect(getTimestamp()).toBe("1 minute ago"); jest.setSystemTime(new Date(Date.UTC(2018, 7, 14, 18, 36, 41))); act(() => { jest.advanceTimersByTime(31 * 1000); }); - expect( - tree - .find("span.components-label.badge.bg-secondary.cursor-pointer") - .at(0) - .text(), - ).toBe("1 hour ago"); + expect(getTimestamp()).toBe("1 hour ago"); jest.setSystemTime(new Date(Date.UTC(2018, 7, 14, 19, 36, 41))); act(() => { jest.advanceTimersByTime(31 * 1000); }); - expect( - tree - .find("span.components-label.badge.bg-secondary.cursor-pointer") - .at(0) - .text(), - ).toBe("2 hours ago"); + expect(getTimestamp()).toBe("2 hours ago"); jest.setSystemTime(new Date(Date.UTC(2018, 7, 16, 19, 36, 41))); act(() => { jest.advanceTimersByTime(31 * 1000); }); - expect( - tree - .find("span.components-label.badge.bg-secondary.cursor-pointer") - .at(0) - .text(), - ).toBe("2 days ago"); + expect(getTimestamp()).toBe("2 days ago"); }); }); diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Annotation/__snapshots__/index.test.tsx.snap b/ui/src/Components/Grid/AlertGrid/AlertGroup/Annotation/__snapshots__/index.test.tsx.snap index 804863402..2864eb661 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Annotation/__snapshots__/index.test.tsx.snap +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Annotation/__snapshots__/index.test.tsx.snap @@ -1,85 +1,96 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` matches snapshot 1`] = ` -" - - - annotation name - -" + + + annotation name + + `; exports[` matches snapshot when visible=false 1`] = ` -" -
    -
    -
    +
    - - - foo + + + foo +
    -
    -" + `; exports[` matches snapshot when visible=true 1`] = ` -" -
    -
    - -
    +
    + - - - - foo: + + + + foo: + - - - - some long text + + + some long text + - +
    -
    -" + `; diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Annotation/index.test.tsx b/ui/src/Components/Grid/AlertGrid/AlertGroup/Annotation/index.test.tsx index c2d45cd0e..7f56f54d8 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Annotation/index.test.tsx +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Annotation/index.test.tsx @@ -1,11 +1,9 @@ -import { shallow, mount } from "enzyme"; - -import toDiffableHtml from "diffable-html"; +import { render, fireEvent } from "@testing-library/react"; import { RenderNonLinkAnnotation, RenderLinkAnnotation } from "."; -const ShallowLinkAnnotation = () => { - return shallow( +const renderLinkAnnotation = () => { + return render( { describe("", () => { it("matches snapshot", () => { - const tree = ShallowLinkAnnotation(); - expect(toDiffableHtml(tree.html())).toMatchSnapshot(); + const { asFragment } = renderLinkAnnotation(); + expect(asFragment()).toMatchSnapshot(); }); it("contains a link", () => { - const tree = ShallowLinkAnnotation(); - const link = tree.find("a[href='http://localhost/foo']"); - expect(link).toHaveLength(1); - expect(link.text()).toMatch(/annotation name/); + const { container } = renderLinkAnnotation(); + const link = container.querySelector("a[href='http://localhost/foo']"); + expect(link).toBeInTheDocument(); + expect(link?.textContent).toMatch(/annotation name/); }); }); const MockAfterUpdate = jest.fn(); -const ShallowNonLinkAnnotation = (visible: boolean) => { - return shallow( +const renderNonLinkAnnotation = (visible: boolean) => { + return render( { ); }; -const MountedNonLinkAnnotation = (visible: boolean) => { - return mount( - , - ); -}; - -const MountedNonLinkAnnotationContainingLink = (visible: boolean) => { - return mount( +const renderNonLinkAnnotationContainingLink = (visible: boolean) => { + return render( { describe("", () => { it("matches snapshot when visible=true", () => { - const tree = ShallowNonLinkAnnotation(true); - expect(toDiffableHtml(tree.html())).toMatchSnapshot(); + const { asFragment } = renderNonLinkAnnotation(true); + expect(asFragment()).toMatchSnapshot(); }); it("contains value when visible=true", () => { - const tree = ShallowNonLinkAnnotation(true); - expect(toDiffableHtml(tree.html())).toMatch(/some long text/); + const { container } = renderNonLinkAnnotation(true); + expect(container.innerHTML).toMatch(/some long text/); }); it("matches snapshot when visible=false", () => { - const tree = ShallowNonLinkAnnotation(false); - expect(toDiffableHtml(tree.html())).toMatchSnapshot(); + const { asFragment } = renderNonLinkAnnotation(false); + expect(asFragment()).toMatchSnapshot(); }); it("doesn't contain value when visible=false", () => { - const tree = ShallowNonLinkAnnotation(false); - expect(toDiffableHtml(tree.html())).not.toMatch(/some long text/); + const { container } = renderNonLinkAnnotation(false); + expect(container.innerHTML).not.toMatch(/some long text/); }); it("links inside annotation are rendered as a.href", () => { - const tree = MountedNonLinkAnnotationContainingLink(true); - const link = tree.find("a[href='http://example.com']"); - expect(link.text()).toBe("http://example.com"); + const { container } = renderNonLinkAnnotationContainingLink(true); + const link = container.querySelector("a[href='http://example.com']"); + expect(link?.textContent).toBe("http://example.com"); }); it("clicking on - icon hides the value", () => { - const tree = MountedNonLinkAnnotation(true); - expect(toDiffableHtml(tree.html())).toMatch(/angle-right/); - expect(toDiffableHtml(tree.html())).toMatch(/some long text/); - tree.find(".fa-angle-right").simulate("click"); - expect(toDiffableHtml(tree.html())).toMatch(/angle-left/); - expect(toDiffableHtml(tree.html())).not.toMatch(/some long text/); + const { container } = renderNonLinkAnnotation(true); + expect(container.innerHTML).toMatch(/angle-right/); + expect(container.innerHTML).toMatch(/some long text/); + const icon = container.querySelector(".fa-angle-right"); + fireEvent.click(icon!); + expect(container.innerHTML).toMatch(/angle-left/); + expect(container.innerHTML).not.toMatch(/some long text/); }); it("clicking on + icon shows the value", () => { - const tree = MountedNonLinkAnnotation(false); - expect(toDiffableHtml(tree.html())).toMatch(/angle-left/); - expect(toDiffableHtml(tree.html())).not.toMatch(/some long text/); - tree.find(".components-grid-annotation").simulate("click"); - expect(toDiffableHtml(tree.html())).toMatch(/angle-right/); - expect(toDiffableHtml(tree.html())).toMatch(/some long text/); + const { container } = renderNonLinkAnnotation(false); + expect(container.innerHTML).toMatch(/angle-left/); + expect(container.innerHTML).not.toMatch(/some long text/); + const annotation = container.querySelector(".components-grid-annotation"); + fireEvent.click(annotation!); + expect(container.innerHTML).toMatch(/angle-right/); + expect(container.innerHTML).toMatch(/some long text/); }); it("escapes HTML when allowHTML=false", () => { - const tree = shallow( + const { container } = render( ", () => { afterUpdate={MockAfterUpdate} />, ); - expect(toDiffableHtml(tree.html())).toMatch( - /<div>inside div<\/div>/, - ); + expect(container.innerHTML).toMatch(/<div>inside div<\/div>/); }); it("doesn't escape HTML when allowHTML=true", () => { - const tree = shallow( + const { container } = render( ", () => { afterUpdate={MockAfterUpdate} />, ); - expect(tree.html()).toMatch(/
    inside div<\/div>/); + expect(container.innerHTML).toMatch(/
    inside div<\/div>/); }); }); diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupFooter/__snapshots__/index.test.tsx.snap b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupFooter/__snapshots__/index.test.tsx.snap index 481d30a5f..d71b52455 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupFooter/__snapshots__/index.test.tsx.snap +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupFooter/__snapshots__/index.test.tsx.snap @@ -1,288 +1,399 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` matches snapshot 1`] = ` -" -