diff --git a/ui/__mocks__/lodash.js b/ui/__mocks__/lodash.js
new file mode 100644
index 000000000..6d9fc6447
--- /dev/null
+++ b/ui/__mocks__/lodash.js
@@ -0,0 +1,11 @@
+// https://github.com/facebook/jest/issues/3465
+
+function debounce(wrapped) {
+ return wrapped;
+}
+
+function throttle(wrapped) {
+ return wrapped;
+}
+
+export { debounce, throttle };
diff --git a/ui/package-lock.json b/ui/package-lock.json
index 60d423e5d..12abbf3a5 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -3386,6 +3386,15 @@
"prop-types": "15.6.2"
}
},
+ "enzyme-to-json": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.3.4.tgz",
+ "integrity": "sha1-Z8YEDpMRgvGDQYry659DIyWKp38=",
+ "dev": true,
+ "requires": {
+ "lodash": "4.17.10"
+ }
+ },
"errno": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
diff --git a/ui/package.json b/ui/package.json
index c04a1fb51..28473c973 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -53,6 +53,7 @@
"devDependencies": {
"enzyme": "3.4.4",
"enzyme-adapter-react-16": "1.2.0",
+ "enzyme-to-json": "3.3.4",
"eslint-plugin-react": "7.11.1",
"jest-fetch-mock": "1.6.5",
"jest-localstorage-mock": "2.2.0",
@@ -60,5 +61,10 @@
"markdownlint-cli": "0.13.0",
"node-sass-chokidar": "1.3.3",
"onchange": "4.1.0"
+ },
+ "jest": {
+ "snapshotSerializers": [
+ "enzyme-to-json/serializer"
+ ]
}
}
diff --git a/ui/src/Components/NavBar/FilterInput/__snapshots__/index.test.js.snap b/ui/src/Components/NavBar/FilterInput/__snapshots__/index.test.js.snap
new file mode 100644
index 000000000..ad75ddc7e
--- /dev/null
+++ b/ui/src/Components/NavBar/FilterInput/__snapshots__/index.test.js.snap
@@ -0,0 +1,95 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` matches snapshot on default render 1`] = `
+
+`;
diff --git a/ui/src/Components/NavBar/FilterInput/index.test.js b/ui/src/Components/NavBar/FilterInput/index.test.js
new file mode 100644
index 000000000..f06b0dd73
--- /dev/null
+++ b/ui/src/Components/NavBar/FilterInput/index.test.js
@@ -0,0 +1,112 @@
+import React from "react";
+
+import { mount, render } from "enzyme";
+
+import { AlertStore, NewUnappliedFilter } from "Stores/AlertStore";
+import { Settings } from "Stores/Settings";
+import { FilterInput } from ".";
+
+let alertStore;
+let settingsStore;
+
+beforeEach(() => {
+ alertStore = new AlertStore([]);
+ settingsStore = new Settings();
+
+ fetch.resetMocks();
+});
+
+const MountedInput = () => {
+ return mount(
+
+ );
+};
+
+describe("", () => {
+ it("matches snapshot on default render", () => {
+ const tree = render(
+
+ );
+ expect(tree).toMatchSnapshot();
+ });
+
+ it("inputStore.ref should be != null after mount", () => {
+ const tree = MountedInput();
+ const instance = tree.instance();
+ expect(instance.inputStore.ref).not.toBeNull();
+ });
+
+ it("onChange should modify inputStore.value", () => {
+ fetch.mockResponseOnce(JSON.stringify([]));
+
+ const tree = MountedInput();
+ tree.find("input").simulate("change", { target: { value: "foo=bar" } });
+ const instance = tree.instance();
+ expect(instance.inputStore.value).toBe("foo=bar");
+ });
+
+ it("submit should modify alertStore.filters", () => {
+ const tree = MountedInput();
+ const instance = tree.instance();
+ instance.inputStore.value = "foo=bar";
+ expect(alertStore.filters.values).toHaveLength(0);
+ tree.find("form").simulate("submit");
+ expect(alertStore.filters.values).toHaveLength(1);
+ expect(alertStore.filters.values[0]).toMatchObject(
+ NewUnappliedFilter("foo=bar")
+ );
+ });
+
+ it("Clicking on form-control div focuses input", () => {
+ const tree = MountedInput();
+ const instance = tree.instance();
+ const inputSpy = jest.spyOn(instance.inputStore.ref.input, "focus");
+ const formControl = tree.find(".form-control");
+ formControl.simulate("click");
+ expect(inputSpy).toHaveBeenCalledTimes(1);
+ });
+});
+
+describe("", () => {
+ it("fetches suggestions on input change", done => {
+ fetch.mockResponseOnce(JSON.stringify(["foo=bar", "foo=~bar"]));
+
+ const tree = MountedInput();
+ const instance = tree.instance();
+ tree.find("input").simulate("change", { target: { value: "foo" } });
+
+ // need to wait on fetch to resolve, but can't find any better way here
+ setTimeout(() => {
+ expect(fetch.mock.calls).toHaveLength(1);
+ expect(fetch.mock.calls[0]).toContain("./autocomplete.json?term=foo");
+ expect(instance.inputStore.suggestions).toHaveLength(2);
+ expect(instance.inputStore.suggestions).toContain("foo=bar");
+ expect(instance.inputStore.suggestions).toContain("foo=~bar");
+ done();
+ }, 1000);
+ });
+
+ it("handles failed suggestion fetches", done => {
+ fetch.mockRejectOnce("Fetch error");
+
+ const tree = MountedInput();
+ const instance = tree.instance();
+ tree.find("input").simulate("change", { target: { value: "bar" } });
+
+ // need to wait on fetch to resolve, but can't find any better way here
+ setTimeout(() => {
+ expect(fetch.mock.calls).toHaveLength(1);
+ expect(fetch.mock.calls[0]).toContain("./autocomplete.json?term=bar");
+ expect(instance.inputStore.suggestions).toHaveLength(0);
+ done();
+ }, 1000);
+ });
+
+ it("clearing input clears suggestions", () => {
+ const tree = MountedInput();
+ const instance = tree.instance();
+ instance.inputStore.suggestions = ["foo", "bar"];
+ tree.find("input").simulate("change", { target: { value: "" } });
+ expect(instance.inputStore.suggestions).toHaveLength(0);
+ });
+});