From 4dfd044cc39327fef422007fc42aed9805aac813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Sat, 1 Sep 2018 19:36:01 +0100 Subject: [PATCH] feat(tests): add Silence component tests --- ui/package-lock.json | 40 ++++ ui/package.json | 2 + .../Silence/__snapshots__/index.test.js.snap | 118 +++++++++++ .../AlertGrid/AlertGroup/Silence/index.js | 2 +- .../AlertGroup/Silence/index.test.js | 194 ++++++++++++++++++ ui/src/setupTests.js | 3 + 6 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/__snapshots__/index.test.js.snap create mode 100644 ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/index.test.js diff --git a/ui/package-lock.json b/ui/package-lock.json index 4e0401444..ace7fd269 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -3100,6 +3100,40 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, + "diffable-html": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/diffable-html/-/diffable-html-3.0.0.tgz", + "integrity": "sha512-lUxHiU00DexR/wKcY56OiJZmB0D66ghidYfU4VxUMG09TDx+1jjO7/dFrZKI2p9z00tWY/7ZeO9BBEi6n0jUYQ==", + "dev": true, + "requires": { + "htmlparser2": "3.9.2" + }, + "dependencies": { + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "htmlparser2": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.4.2", + "domutils": "1.5.1", + "entities": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.6" + } + } + } + }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -6534,6 +6568,12 @@ "pretty-format": "20.0.3" } }, + "jest-date-mock": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/jest-date-mock/-/jest-date-mock-1.0.3.tgz", + "integrity": "sha512-PLwqL0KI+zDKc6SoytvApudwFD8uDLOM7Bf4Z5C3KpJrHDJv5RawgSZUQOUqSukQ+TOhdHzliUOvGtE3aA+fWA==", + "dev": true + }, "jest-diff": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-20.0.3.tgz", diff --git a/ui/package.json b/ui/package.json index cc5f4caac..3a20f3b8f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -51,11 +51,13 @@ "watch-css": "npm run build-css && node_modules/.bin/node-sass-chokidar src/ -o src/ --watch --recursive" }, "devDependencies": { + "diffable-html": "3.0.0", "enzyme": "3.5.0", "enzyme-adapter-react-16": "1.3.1", "enzyme-to-json": "3.3.4", "eslint-plugin-react": "7.11.1", "jest-canvas-mock": "1.1.0", + "jest-date-mock": "1.0.3", "jest-fetch-mock": "1.6.5", "jest-localstorage-mock": "2.2.0", "jest-mock-console": "0.4.0", diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/__snapshots__/index.test.js.snap b/ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/__snapshots__/index.test.js.snap new file mode 100644 index 000000000..2c7daac4d --- /dev/null +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/__snapshots__/index.test.js.snap @@ -0,0 +1,118 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` matches snapshot when data is not present in alertStore 1`] = ` +" +
+ + Silenced by default/4cf5fd82-1edd-4169-99d1-ff8415e72179 + +
+" +`; + +exports[` matches snapshot when data is present in alertStore 1`] = ` +" +
+
+ + Fake silence + + + + + + + + + me@example.com + + + Expires + +
+
+
+
+
+
+
+
+
+" +`; + +exports[` matches snapshot with expaned details 1`] = ` +" +
+
+ + Fake silence + + + + + + + + + me@example.com + + + +
+
+ + @alertmanager: default + + + 4cf5fd82-1edd-4169-99d1-ff8415e72179 + + + Silenced + + + + Expires + + + + alertname=MockAlert + +
+
+" +`; diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/index.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/index.js index e546a1280..a265583e9 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/index.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/index.js @@ -228,4 +228,4 @@ const Silence = inject("alertStore")( ) ); -export { Silence }; +export { Silence, SilenceDetails, SilenceExpiryBadgeWithProgress }; diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/index.test.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/index.test.js new file mode 100644 index 000000000..56ddd651b --- /dev/null +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Silence/index.test.js @@ -0,0 +1,194 @@ +import React from "react"; + +import { Provider } from "mobx-react"; + +import { mount, shallow } from "enzyme"; + +import toDiffableHtml from "diffable-html"; + +import { advanceTo, clear } from "jest-date-mock"; + +import { AlertStore } from "Stores/AlertStore"; +import { Silence, SilenceDetails, SilenceExpiryBadgeWithProgress } from "."; + +const mockAfterUpdate = jest.fn(); + +const alertmanager = { + name: "default", + uri: "file:///mock", + state: "suppressed", + startsAt: "2000-01-01T10:00:00Z", + endsAt: "0001-01-01T00:00:00Z", + source: "localhost/prometheus", + silencedBy: ["4cf5fd82-1edd-4169-99d1-ff8415e72179"] +}; + +const silence = { + id: "4cf5fd82-1edd-4169-99d1-ff8415e72179", + matchers: [ + { + name: "alertname", + value: "MockAlert", + isRegex: false + } + ], + startsAt: "2000-01-01T10:00:00Z", + endsAt: "2000-01-01T20:00:00Z", + createdAt: "0001-01-01T00:00:00Z", + createdBy: "me@example.com", + comment: "Fake silence", + jiraID: "", + jiraURL: "" +}; + +let alertStore; + +beforeEach(() => { + advanceTo(new Date(2000, 0, 1, 15, 0, 0)); + alertStore = new AlertStore([]); + alertStore.data.upstreams = { + counters: { + total: 1, + healthy: 1, + failed: 0 + }, + instances: [ + { + name: "default", + uri: "file:///mock", + error: "" + } + ] + }; + alertStore.data.silences = { + default: { + "4cf5fd82-1edd-4169-99d1-ff8415e72179": silence + } + }; +}); + +afterEach(() => { + // reset Date() to current time + clear(); +}); + +const MountedSilence = () => { + return mount( + + + + ); +}; + +describe("", () => { + it("matches snapshot when data is present in alertStore", () => { + const tree = MountedSilence().find("Silence"); + expect(toDiffableHtml(tree.html())).toMatchSnapshot(); + }); + + it("renders full silence when data is present in alertStore", () => { + const tree = MountedSilence().find("Silence"); + const fallback = tree.find("FallbackSilenceDesciption"); + expect(fallback).toHaveLength(0); + }); + + it("matches snapshot when data is not present in alertStore", () => { + alertStore.data.silences = {}; + const tree = MountedSilence().find("Silence"); + expect(toDiffableHtml(tree.html())).toMatchSnapshot(); + }); + + it("renders FallbackSilenceDesciption when Alertmanager data is not present in alertStore", () => { + alertStore.data.silences = {}; + const tree = MountedSilence(); + const fallback = tree.find("FallbackSilenceDesciption"); + expect(fallback).toHaveLength(1); + expect(tree.text()).toBe( + "Silenced by default/4cf5fd82-1edd-4169-99d1-ff8415e72179" + ); + }); + + it("renders FallbackSilenceDesciption when silence data is not present in alertStore", () => { + alertStore.data.silences.default = {}; + const tree = MountedSilence(); + const fallback = tree.find("FallbackSilenceDesciption"); + expect(fallback).toHaveLength(1); + expect(tree.text()).toBe( + "Silenced by default/4cf5fd82-1edd-4169-99d1-ff8415e72179" + ); + }); + + it("clicking on expand toggle shows silence details", () => { + const tree = MountedSilence(); + const toggle = tree.find("a.float-right.cursor-pointer"); + toggle.simulate("click"); + const details = tree.find("SilenceDetails"); + expect(details).toHaveLength(1); + }); + + it("matches snapshot with expaned details", () => { + const tree = MountedSilence().find("Silence"); + tree.instance().collapse.toggle(); + expect(toDiffableHtml(tree.html())).toMatchSnapshot(); + }); + + it("renders comment as link when jiraURL is set", () => { + alertStore.data.silences.default[silence.id].jiraURL = + "http://jira.example.com"; + const tree = MountedSilence().find("Silence"); + const link = tree.find("a[href='http://jira.example.com']"); + expect(link).toHaveLength(1); + expect(link.text()).toBe("Fake silence"); + }); +}); + +const ShallowSilenceDetails = () => { + return shallow( + + ); +}; + +describe("", () => { + it("unexpired silence endsAt label uses 'secondary' class", () => { + const tree = ShallowSilenceDetails(); + const endsAt = tree.find("span.badge").at(1); + expect(endsAt.html()).toMatch(/badge-secondary/); + }); + + it("expired silence endsAt label uses 'danger' class", () => { + advanceTo(new Date(2000, 0, 1, 23, 0, 0)); + const tree = ShallowSilenceDetails(); + const endsAt = tree.find("span.badge").at(1); + expect(endsAt.html()).toMatch(/badge-danger/); + }); +}); + +const ShallowSilenceExpiryBadgeWithProgress = () => { + return shallow(); +}; + +describe("", () => { + it("renders with class 'danger' and no progressbar when expired", () => { + advanceTo(new Date(2001, 0, 1, 23, 0, 0)); + const tree = ShallowSilenceExpiryBadgeWithProgress(); + expect(tree.html()).toMatch(/badge-danger/); + expect(tree.text()).toBe("Expired "); + }); + + it("progressbar uses class 'danger' when > 90%", () => { + advanceTo(new Date(2000, 0, 1, 19, 30, 0)); + const tree = ShallowSilenceExpiryBadgeWithProgress(); + expect(tree.html()).toMatch(/progress-bar bg-danger/); + }); + + it("progressbar uses class 'danger' when > 75%", () => { + advanceTo(new Date(2000, 0, 1, 17, 45, 0)); + const tree = ShallowSilenceExpiryBadgeWithProgress(); + expect(tree.html()).toMatch(/progress-bar bg-warning/); + }); +}); diff --git a/ui/src/setupTests.js b/ui/src/setupTests.js index a18bc9688..da247227d 100644 --- a/ui/src/setupTests.js +++ b/ui/src/setupTests.js @@ -15,6 +15,9 @@ require("jest-localstorage-mock"); // favico.js needs canvas require("jest-canvas-mock"); +// used to mock current time since we render moment.fromNow() in some places +require("jest-date-mock"); + // fetch is used in multiple places to interact with Go backend // or upstream Alertmanager API global.fetch = require("jest-fetch-mock");