From 186039474361e0f1fc56bd413a4ae4c35ed1d818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Sat, 25 Aug 2018 22:15:49 +0100 Subject: [PATCH 01/16] feat(tests): add missing tests for main modal --- ui/src/Components/MainModal/index.test.js | 41 +++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/ui/src/Components/MainModal/index.test.js b/ui/src/Components/MainModal/index.test.js index 79b6e5ee6..fc0a699d6 100644 --- a/ui/src/Components/MainModal/index.test.js +++ b/ui/src/Components/MainModal/index.test.js @@ -1,6 +1,6 @@ import React from "react"; -import { shallow } from "enzyme"; +import { shallow, mount } from "enzyme"; import { AlertStore } from "Stores/AlertStore"; import { Settings } from "Stores/Settings"; @@ -14,27 +14,33 @@ beforeEach(() => { settingsStore = new Settings(); }); -const RenderMainModal = () => { +const ShallowMainModal = () => { return shallow( ); }; +const MountedMainModal = () => { + return mount( + + ); +}; + describe("", () => { it("only renders FontAwesomeIcon when modal is not shown", () => { - const tree = RenderMainModal(); + const tree = ShallowMainModal(); expect(tree.text()).toBe(""); }); it("renders the modal when it is shown", () => { - const tree = RenderMainModal(); + const tree = ShallowMainModal(); const toggle = tree.find(".nav-link"); toggle.simulate("click"); expect(tree.text()).toBe(""); }); it("hides the modal when toggle() is called twice", () => { - const tree = RenderMainModal(); + const tree = ShallowMainModal(); const toggle = tree.find(".nav-link"); toggle.simulate("click"); toggle.simulate("click"); @@ -42,7 +48,7 @@ describe("", () => { }); it("hides the modal when hide() is called", () => { - const tree = RenderMainModal(); + const tree = ShallowMainModal(); const toggle = tree.find(".nav-link"); toggle.simulate("click"); expect(tree.text()).toBe(""); @@ -50,4 +56,27 @@ describe("", () => { instance.toggle.hide(); expect(tree.text()).toBe(""); }); + + it("'modal-open' class is appended to body node when modal is visible", () => { + const tree = MountedMainModal(); + const toggle = tree.find(".nav-link"); + toggle.simulate("click"); + expect(document.body.className.split(" ")).toContain("modal-open"); + }); + + it("'modal-open' class is removed from body node after modal is hidden", () => { + const tree = MountedMainModal(); + const toggle = tree.find(".nav-link"); + toggle.simulate("click"); + toggle.simulate("click"); + expect(document.body.className.split(" ")).not.toContain("modal-open"); + }); + + it("'modal-open' class is removed from body node after modal is unmounted", () => { + const tree = MountedMainModal(); + const toggle = tree.find(".nav-link"); + toggle.simulate("click"); + tree.unmount(); + expect(document.body.className.split(" ")).not.toContain("modal-open"); + }); }); From 3dfeb7e360230dc3dbbf62cb8c932d793fbcea05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Sat, 25 Aug 2018 22:21:46 +0100 Subject: [PATCH 02/16] feat(tests): add tests for the root SilenceModal component --- ui/src/Components/SilenceModal/index.test.js | 81 ++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 ui/src/Components/SilenceModal/index.test.js diff --git a/ui/src/Components/SilenceModal/index.test.js b/ui/src/Components/SilenceModal/index.test.js new file mode 100644 index 000000000..272925fa9 --- /dev/null +++ b/ui/src/Components/SilenceModal/index.test.js @@ -0,0 +1,81 @@ +import React from "react"; + +import { shallow, mount } from "enzyme"; + +import { AlertStore } from "Stores/AlertStore"; +import { SilenceFormStore } from "Stores/SilenceFormStore"; +import { SilenceModal } from "."; + +let alertStore; +let silenceFormStore; + +beforeEach(() => { + alertStore = new AlertStore([]); + silenceFormStore = new SilenceFormStore(); +}); + +const ShallowSilenceModal = () => { + return shallow( + + ); +}; + +const MountedSilenceModal = () => { + return mount( + + ); +}; + +describe("", () => { + it("only renders FontAwesomeIcon when modal is not shown", () => { + const tree = ShallowSilenceModal(); + expect(tree.text()).toBe(""); + }); + + it("renders the modal when it is shown", () => { + const tree = ShallowSilenceModal(); + const toggle = tree.find(".nav-link"); + toggle.simulate("click"); + expect(tree.text()).toBe(""); + }); + + it("hides the modal when toggle() is called twice", () => { + const tree = ShallowSilenceModal(); + const toggle = tree.find(".nav-link"); + toggle.simulate("click"); + toggle.simulate("click"); + expect(tree.text()).toBe(""); + }); + + it("hides the modal when hide() is called", () => { + const tree = ShallowSilenceModal(); + const toggle = tree.find(".nav-link"); + toggle.simulate("click"); + expect(tree.text()).toBe(""); + silenceFormStore.toggle.hide(); + expect(tree.text()).toBe(""); + }); + + it("'modal-open' class is appended to body node when modal is visible", () => { + const tree = MountedSilenceModal(); + const toggle = tree.find(".nav-link"); + toggle.simulate("click"); + expect(document.body.className.split(" ")).toContain("modal-open"); + }); + + it("'modal-open' class is removed from body node after modal is hidden", () => { + const tree = MountedSilenceModal(); + const toggle = tree.find(".nav-link"); + toggle.simulate("click"); + toggle.simulate("click"); + expect(document.body.className.split(" ")).not.toContain("modal-open"); + }); + + it("'modal-open' class is removed from body node after modal is unmounted", () => { + const tree = MountedSilenceModal(); + const toggle = tree.find(".nav-link"); + toggle.simulate("click"); + tree.unmount(); + expect(document.body.className.split(" ")).not.toContain("modal-open"); + }); +}); From a99b453337c7b4632ff83776d47b711266a0c582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Sat, 25 Aug 2018 22:58:03 +0100 Subject: [PATCH 03/16] feat(tests): add tests for SilencePreview --- .../SilenceModal/SilencePreview.test.js | 21 ++++++ .../__snapshots__/SilencePreview.test.js.snap | 73 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 ui/src/Components/SilenceModal/SilencePreview.test.js create mode 100644 ui/src/Components/SilenceModal/__snapshots__/SilencePreview.test.js.snap diff --git a/ui/src/Components/SilenceModal/SilencePreview.test.js b/ui/src/Components/SilenceModal/SilencePreview.test.js new file mode 100644 index 000000000..43be7a081 --- /dev/null +++ b/ui/src/Components/SilenceModal/SilencePreview.test.js @@ -0,0 +1,21 @@ +import React from "react"; + +import { render } from "enzyme"; + +import moment from "moment"; + +import { SilenceFormStore } from "Stores/SilenceFormStore"; +import { SilencePreview } from "./SilencePreview"; + +describe("", () => { + it("matches snapshot", () => { + const silenceFormStore = new SilenceFormStore(); + silenceFormStore.data.startsAt = moment([2000, 1, 1, 0, 0, 0]); + silenceFormStore.data.endsAt = moment([2000, 1, 1, 1, 0, 0]); + silenceFormStore.data.createdBy = "me@example.com"; + silenceFormStore.data.comment = "SilencePreview test"; + + const tree = render(); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/ui/src/Components/SilenceModal/__snapshots__/SilencePreview.test.js.snap b/ui/src/Components/SilenceModal/__snapshots__/SilencePreview.test.js.snap new file mode 100644 index 000000000..d884d9fff --- /dev/null +++ b/ui/src/Components/SilenceModal/__snapshots__/SilencePreview.test.js.snap @@ -0,0 +1,73 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` matches snapshot 1`] = ` +
+
+    {
+      "
+    
+      matchers
+    
+    ": [],
+      "
+    
+      startsAt
+    
+    ": 
+    
+      "2000-02-01T00:00:00.000Z"
+    
+    ,
+      "
+    
+      endsAt
+    
+    ": 
+    
+      "2000-02-01T01:00:00.000Z"
+    
+    ,
+      "
+    
+      createdBy
+    
+    ": 
+    
+      ""
+    
+    ,
+      "
+    
+      comment
+    
+    ": 
+    
+      "SilencePreview test"
+    
+    
+    }
+  
+
+`; From 2f04d61abed7be5aabe6cb14426529300cbc2da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Sat, 25 Aug 2018 23:54:04 +0100 Subject: [PATCH 04/16] refactor(tests): migrate tests to enzyme --- .../Labels/FilterInputLabel/index.test.js | 50 +++++++++---------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/ui/src/Components/Labels/FilterInputLabel/index.test.js b/ui/src/Components/Labels/FilterInputLabel/index.test.js index 0f5e19c92..0fab42590 100644 --- a/ui/src/Components/Labels/FilterInputLabel/index.test.js +++ b/ui/src/Components/Labels/FilterInputLabel/index.test.js @@ -1,5 +1,6 @@ import React from "react"; -import renderer from "react-test-renderer"; + +import { shallow, mount } from "enzyme"; import { AlertStore, NewUnappliedFilter } from "Stores/AlertStore"; @@ -22,7 +23,7 @@ const MockColors = () => { }; }; -const FakeLabel = (matcher, applied) => { +const ShallowLabel = (matcher, applied) => { const name = "foo"; const value = "bar"; const filter = NewUnappliedFilter(`${name}${matcher}${value}`); @@ -30,27 +31,22 @@ const FakeLabel = (matcher, applied) => { filter.name = name; filter.matcher = matcher; filter.value = value; - return renderer.create( - - ); + return shallow(); }; const ValidateClass = (matcher, applied, expectedClass) => { - const tree = FakeLabel(matcher, applied).toJSON(); - expect(tree.props.className.split(" ")).toContain(expectedClass); + const tree = ShallowLabel(matcher, applied); + expect(tree.props().className.split(" ")).toContain(expectedClass); }; const ValidateOnChange = newRaw => { - const component = renderer.create( + const tree = shallow( ); - const tree = component.toTree(); - - // call onChange with new raw value - tree.instance.onChange({ raw: newRaw }); + tree.instance().onChange({ raw: newRaw }); return tree; }; @@ -92,40 +88,40 @@ describe(" className", () => { describe(" style", () => { it("unapplied filter with color information and '=' matcher should have empty style", () => { MockColors(); - const tree = FakeLabel("=", false).toJSON(); - expect(tree.props.style).toMatchObject({}); + const tree = ShallowLabel("=", false); + expect(tree.props().style).toMatchObject({}); }); it("unapplied filter with no color information and '=' matcher should have empty style", () => { - const tree = FakeLabel("=", false).toJSON(); - expect(tree.props.style).toMatchObject({}); + const tree = ShallowLabel("=", false); + expect(tree.props().style).toMatchObject({}); }); it("unapplied filter with no color information and any matcher other than '=' should have empty style", () => { for (const matcher of NonEqualMatchers) { - const tree = FakeLabel(matcher, false).toJSON(); - expect(tree.props.style).toMatchObject({}); + const tree = ShallowLabel(matcher, false); + expect(tree.props().style).toMatchObject({}); } }); it("applied filter with color information and '=' matcher should have non empty style", () => { MockColors(); - const tree = FakeLabel("=", true).toJSON(); - expect(tree.props.style).toMatchObject({ + const tree = ShallowLabel("=", true); + expect(tree.props().style).toMatchObject({ color: "rgba(1, 2, 3, 100)", backgroundColor: "rgba(4, 5, 6, 200)" }); }); it("applied filter with no color information and '=' matcher should have empty style", () => { - const tree = FakeLabel("=", true).toJSON(); - expect(tree.props.style).toMatchObject({}); + const tree = ShallowLabel("=", true); + expect(tree.props().style).toMatchObject({}); }); it("applied filter with no color information and any matcher other than '=' should have empty style", () => { for (const matcher of NonEqualMatchers) { - const tree = FakeLabel(matcher, true).toJSON(); - expect(tree.props.style).toMatchObject({}); + const tree = ShallowLabel(matcher, true); + expect(tree.props().style).toMatchObject({}); } }); }); @@ -168,14 +164,14 @@ describe(" onChange", () => { NewUnappliedFilter("foo=bar"), NewUnappliedFilter("bar=baz") ]; - const component = renderer.create( + const tree = mount( ); - const button = component.root.findByType("button"); - button.props.onClick(); + const button = tree.find("button"); + button.simulate("click"); expect(alertStore.filters.values).toHaveLength(1); expect(alertStore.filters.values).toContainEqual( NewUnappliedFilter("bar=baz") From 10f841c7de0c2bcc7b7968033ba30bca79be073c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Sun, 26 Aug 2018 00:03:54 +0100 Subject: [PATCH 05/16] refactor(tests): missing test coverage --- .../Labels/FilterInputLabel/index.test.js | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/ui/src/Components/Labels/FilterInputLabel/index.test.js b/ui/src/Components/Labels/FilterInputLabel/index.test.js index 0fab42590..ac0daa404 100644 --- a/ui/src/Components/Labels/FilterInputLabel/index.test.js +++ b/ui/src/Components/Labels/FilterInputLabel/index.test.js @@ -23,7 +23,7 @@ const MockColors = () => { }; }; -const ShallowLabel = (matcher, applied) => { +const ShallowLabel = (matcher, applied, valid) => { const name = "foo"; const value = "bar"; const filter = NewUnappliedFilter(`${name}${matcher}${value}`); @@ -31,11 +31,12 @@ const ShallowLabel = (matcher, applied) => { filter.name = name; filter.matcher = matcher; filter.value = value; + filter.isValid = valid; return shallow(); }; const ValidateClass = (matcher, applied, expectedClass) => { - const tree = ShallowLabel(matcher, applied); + const tree = ShallowLabel(matcher, applied, true); expect(tree.props().className.split(" ")).toContain(expectedClass); }; @@ -88,25 +89,25 @@ describe(" className", () => { describe(" style", () => { it("unapplied filter with color information and '=' matcher should have empty style", () => { MockColors(); - const tree = ShallowLabel("=", false); + const tree = ShallowLabel("=", false, true); expect(tree.props().style).toMatchObject({}); }); it("unapplied filter with no color information and '=' matcher should have empty style", () => { - const tree = ShallowLabel("=", false); + const tree = ShallowLabel("=", false, true); expect(tree.props().style).toMatchObject({}); }); it("unapplied filter with no color information and any matcher other than '=' should have empty style", () => { for (const matcher of NonEqualMatchers) { - const tree = ShallowLabel(matcher, false); + const tree = ShallowLabel(matcher, false, true); expect(tree.props().style).toMatchObject({}); } }); it("applied filter with color information and '=' matcher should have non empty style", () => { MockColors(); - const tree = ShallowLabel("=", true); + const tree = ShallowLabel("=", true, true); expect(tree.props().style).toMatchObject({ color: "rgba(1, 2, 3, 100)", backgroundColor: "rgba(4, 5, 6, 200)" @@ -114,13 +115,13 @@ describe(" style", () => { }); it("applied filter with no color information and '=' matcher should have empty style", () => { - const tree = ShallowLabel("=", true); + const tree = ShallowLabel("=", true, true); expect(tree.props().style).toMatchObject({}); }); it("applied filter with no color information and any matcher other than '=' should have empty style", () => { for (const matcher of NonEqualMatchers) { - const tree = ShallowLabel(matcher, true); + const tree = ShallowLabel(matcher, true, true); expect(tree.props().style).toMatchObject({}); } }); @@ -178,3 +179,13 @@ describe(" onChange", () => { ); }); }); + +describe(" render", () => { + it("invalid filter matches snapshot", () => { + const tree = ShallowLabel("=", true, false); + const errorSpan = tree.find(".text-danger"); + expect(errorSpan).toHaveLength(1); + const errorIcon = errorSpan.find("FontAwesomeIcon"); + expect(errorIcon).toHaveLength(1); + }); +}); From dced537adb38b2d306cc6224c5463ced9be54001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Sun, 26 Aug 2018 16:18:21 +0100 Subject: [PATCH 06/16] feat(tests): add missing navbar test for resize events --- ui/src/Components/NavBar/index.js | 8 ++++---- ui/src/Components/NavBar/index.test.js | 20 +++++++++++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/ui/src/Components/NavBar/index.js b/ui/src/Components/NavBar/index.js index 7d9c551c5..92e617587 100644 --- a/ui/src/Components/NavBar/index.js +++ b/ui/src/Components/NavBar/index.js @@ -15,8 +15,8 @@ import { SilenceModal } from "Components/SilenceModal"; import "./index.css"; -const navbarResize = function(width, height) { - document.body.style["padding-top"] = height + 4 + "px"; +const NavbarOnResize = function(width, height) { + document.body.style["padding-top"] = `${height + 4}px`; }; const NavBar = observer( @@ -41,7 +41,7 @@ const NavBar = observer( return (