Merge pull request #61 from prymitive/ui-tests

feat(test): more test coverage for labels
This commit is contained in:
Łukasz Mierzwa
2018-08-21 23:33:50 +01:00
committed by GitHub
7 changed files with 261 additions and 15 deletions

6
ui/package-lock.json generated
View File

@@ -6355,6 +6355,12 @@
"p-map": "1.2.0"
}
},
"jest-localstorage-mock": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/jest-localstorage-mock/-/jest-localstorage-mock-2.2.0.tgz",
"integrity": "sha512-x+P0vcwr4540bCAYzTEpiD9rs+zh/QZzyiABV+MU6yM2OPwPlrrLyUx/6gValMyt6tg5lX6Z53o2rHWfUht5Xw==",
"dev": true
},
"jest-matcher-utils": {
"version": "20.0.3",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-20.0.3.tgz",

View File

@@ -52,6 +52,7 @@
},
"devDependencies": {
"eslint-plugin-react": "7.11.1",
"jest-localstorage-mock": "2.2.0",
"markdownlint-cli": "0.13.0",
"node-sass-chokidar": "1.3.3",
"onchange": "4.1.0",

View File

@@ -28,7 +28,7 @@ const Fetcher = observer(
this.interval = newInterval;
this.timer = setInterval(
() => alertStore.fetch(),
() => alertStore.fetchWithThrottle(),
this.interval * 1000
);
}
@@ -37,7 +37,7 @@ const Fetcher = observer(
componentDidUpdate() {
const { alertStore } = this.props;
alertStore.fetch();
alertStore.fetchWithThrottle();
this.setTimer();
}
@@ -45,7 +45,7 @@ const Fetcher = observer(
componentDidMount() {
const { alertStore } = this.props;
alertStore.fetch();
alertStore.fetchWithThrottle();
this.setTimer();
}

View File

@@ -0,0 +1,124 @@
import React from "react";
import renderer from "react-test-renderer";
import { FetchMock, EmptyAPIResponse } from "__mocks__/Fetch";
import { AlertStore } from "Stores/AlertStore";
import { Settings } from "Stores/Settings";
import { Fetcher } from ".";
beforeAll(() => {
jest.useFakeTimers();
});
let alertStore;
let settingsStore;
beforeEach(() => {
const response = EmptyAPIResponse();
global.fetch = FetchMock(response);
alertStore = new AlertStore(["label=value"]);
settingsStore = new Settings();
});
afterEach(() => {
jest.clearAllTimers();
global.fetch.mockRestore();
});
describe("<Fetcher />", () => {
it("renders correctly with 'label=value' filter", () => {
const tree = renderer
.create(<Fetcher alertStore={alertStore} settingsStore={settingsStore} />)
.toJSON();
expect(tree.props["data-filters"]).toBe("label=value");
expect(tree.props["data-interval"]).toBe(30);
});
it("re-renders on fetch interval change", () => {
const fetcher = renderer.create(
<Fetcher alertStore={alertStore} settingsStore={settingsStore} />
);
expect(fetcher.toJSON().props["data-interval"]).toBe(30);
settingsStore.fetchConfig.config.interval = 60;
expect(fetcher.toJSON().props["data-interval"]).toBe(60);
});
it("re-renders on filters change", () => {
const fetcher = renderer.create(
<Fetcher alertStore={alertStore} settingsStore={settingsStore} />
);
expect(fetcher.toJSON().props["data-filters"]).toBe("label=value");
alertStore.filters.values = [];
expect(fetcher.toJSON().props["data-filters"]).toBe("");
});
it("calls alertStore.fetchWithThrottle on mount", () => {
const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle");
renderer.create(
<Fetcher alertStore={alertStore} settingsStore={settingsStore} />
);
expect(fetchSpy).toHaveBeenCalledTimes(1);
});
it("calls alertStore.fetchWithThrottle again after interval change", () => {
const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle");
renderer.create(
<Fetcher alertStore={alertStore} settingsStore={settingsStore} />
);
settingsStore.fetchConfig.config.interval = 60;
expect(fetchSpy).toHaveBeenCalledTimes(2);
});
it("calls alertStore.fetchWithThrottle again after filter change", () => {
const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle");
renderer.create(
<Fetcher alertStore={alertStore} settingsStore={settingsStore} />
);
alertStore.filters.values = [];
expect(fetchSpy).toHaveBeenCalledTimes(2);
});
it("keeps calling alertStore.fetchWithThrottle after running pending timers", () => {
const fetchSpy = jest.spyOn(alertStore, "fetchWithThrottle");
renderer.create(
<Fetcher alertStore={alertStore} settingsStore={settingsStore} />
);
jest.runOnlyPendingTimers();
expect(fetchSpy).toHaveBeenCalledTimes(2);
jest.runOnlyPendingTimers();
expect(fetchSpy).toHaveBeenCalledTimes(3);
jest.runOnlyPendingTimers();
expect(fetchSpy).toHaveBeenCalledTimes(4);
});
it("internal timer is armed after render", () => {
const fetcher = renderer.create(
<Fetcher alertStore={alertStore} settingsStore={settingsStore} />
);
const instance = fetcher.getInstance();
expect(instance.timer).toBeGreaterThanOrEqual(0);
});
it("internal timer is null after unmount", () => {
const fetcher = renderer.create(
<Fetcher alertStore={alertStore} settingsStore={settingsStore} />
);
const instance = fetcher.getInstance();
instance.componentWillUnmount();
expect(instance.timer).toBeNull();
});
});

View File

@@ -0,0 +1,112 @@
import React from "react";
import renderer from "react-test-renderer";
import { AlertStore } from "Stores/AlertStore";
import { FilteringCounterBadge } from ".";
let alertStore;
beforeEach(() => {
alertStore = new AlertStore([]);
});
const validateClassName = (value, className) => {
const tree = renderer
.create(
<FilteringCounterBadge
alertStore={alertStore}
name="@state"
value={value}
counter={1}
/>
)
.toJSON();
expect(tree.props.className.split(" ")).toContain(className);
};
const validateStyle = value => {
const tree = renderer
.create(
<FilteringCounterBadge
alertStore={alertStore}
name="@state"
value={value}
counter={1}
/>
)
.toJSON();
expect(tree.props.style).toMatchObject({});
};
const validateOnClick = value => {
const tree = renderer
.create(
<FilteringCounterBadge
alertStore={alertStore}
name="@state"
value={value}
counter={1}
/>
)
.toJSON();
tree.props.onClick({ preventDefault: () => {} });
expect(alertStore.filters.values).toHaveLength(1);
expect(alertStore.filters.values).toContainEqual({
applied: false,
isValid: true,
raw: `@state=${value}`,
hits: 0,
name: "",
matcher: "",
value: ""
});
};
describe("<FilteringCounterBadge />", () => {
it("@state=unprocessed counter badge should have className 'badge-secondary'", () => {
validateClassName("unprocessed", "badge-secondary");
});
it("@state=active counter badge should have className 'badge-secondary'", () => {
validateClassName("active", "badge-danger");
});
it("@state=suppressed counter badge should have className 'badge-secondary'", () => {
validateClassName("suppressed", "badge-success");
});
it("@state=unprocessed counter badge should have empty style", () => {
validateStyle("unprocessed");
});
it("@state=active counter badge should have empty style", () => {
validateStyle("active");
});
it("@state=suppressed counter badge should have empty style", () => {
validateStyle("suppressed");
});
it("counter badge should have correct children based on the counter prop value", () => {
const tree = renderer
.create(
<FilteringCounterBadge
alertStore={alertStore}
name="@state"
value="active"
counter={123}
/>
)
.toJSON();
expect(tree.children).toEqual(["123"]);
});
it("onClick method on @state=unprocessed counter badge should add a new filter", () => {
validateOnClick("unprocessed");
});
it("onClick method on @state=active counter badge should add a new filter", () => {
validateOnClick("active");
});
it("onClick method on @state=suppressed counter badge should add a new filter", () => {
validateOnClick("suppressed");
});
});

View File

@@ -212,7 +212,7 @@ class AlertStore {
});
});
fetchWithThrottle = throttle(this.fetch, 500);
fetchWithThrottle = throttle(this.fetch, 300);
parseAPIResponse = action(result => {
if (result.error) {
@@ -220,18 +220,20 @@ class AlertStore {
return;
}
const queryFilters = new Set(
this.filters.values
.map(f => f.raw)
.slice()
.sort()
);
const responseFilters = new Set(result.filters.map(m => m.text).sort());
if (
JSON.stringify([...queryFilters]) !== JSON.stringify([...responseFilters])
) {
const queryFilters = [
...new Set(
this.filters.values
.map(f => f.raw)
.slice()
.sort()
)
];
const responseFilters = [
...new Set(result.filters.map(m => m.text).sort())
];
if (JSON.stringify(queryFilters) !== JSON.stringify(responseFilters)) {
console.info(
`Got response with filters=${responseFilters} while expecting results for ${queryFilters}, ignoring`
`Got response with filters '${responseFilters}' while expecting results for '${queryFilters}', ignoring`
);
return;
}

1
ui/src/setupTests.js Normal file
View File

@@ -0,0 +1 @@
require("jest-localstorage-mock");