mirror of
https://github.com/prymitive/karma
synced 2026-05-09 03:36:44 +00:00
Merge pull request #70 from prymitive/tests-5
feat(tests): add missing tests for main modal
This commit is contained in:
@@ -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, valid) => {
|
||||
const name = "foo";
|
||||
const value = "bar";
|
||||
const filter = NewUnappliedFilter(`${name}${matcher}${value}`);
|
||||
@@ -30,27 +31,23 @@ const FakeLabel = (matcher, applied) => {
|
||||
filter.name = name;
|
||||
filter.matcher = matcher;
|
||||
filter.value = value;
|
||||
return renderer.create(
|
||||
<FilterInputLabel alertStore={alertStore} filter={filter} />
|
||||
);
|
||||
filter.isValid = valid;
|
||||
return shallow(<FilterInputLabel alertStore={alertStore} filter={filter} />);
|
||||
};
|
||||
|
||||
const ValidateClass = (matcher, applied, expectedClass) => {
|
||||
const tree = FakeLabel(matcher, applied).toJSON();
|
||||
expect(tree.props.className.split(" ")).toContain(expectedClass);
|
||||
const tree = ShallowLabel(matcher, applied, true);
|
||||
expect(tree.props().className.split(" ")).toContain(expectedClass);
|
||||
};
|
||||
|
||||
const ValidateOnChange = newRaw => {
|
||||
const component = renderer.create(
|
||||
const tree = shallow(
|
||||
<FilterInputLabel
|
||||
alertStore={alertStore}
|
||||
filter={alertStore.filters.values[0]}
|
||||
/>
|
||||
);
|
||||
const tree = component.toTree();
|
||||
|
||||
// call onChange with new raw value
|
||||
tree.instance.onChange({ raw: newRaw });
|
||||
tree.instance().onChange({ raw: newRaw });
|
||||
|
||||
return tree;
|
||||
};
|
||||
@@ -92,40 +89,40 @@ describe("<FilterInputLabel /> className", () => {
|
||||
describe("<FilterInputLabel /> 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, true);
|
||||
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, 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 = FakeLabel(matcher, false).toJSON();
|
||||
expect(tree.props.style).toMatchObject({});
|
||||
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 = FakeLabel("=", true).toJSON();
|
||||
expect(tree.props.style).toMatchObject({
|
||||
const tree = ShallowLabel("=", true, 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, 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, true);
|
||||
expect(tree.props().style).toMatchObject({});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -168,17 +165,27 @@ describe("<FilterInputLabel /> onChange", () => {
|
||||
NewUnappliedFilter("foo=bar"),
|
||||
NewUnappliedFilter("bar=baz")
|
||||
];
|
||||
const component = renderer.create(
|
||||
const tree = mount(
|
||||
<FilterInputLabel
|
||||
alertStore={alertStore}
|
||||
filter={alertStore.filters.values[0]}
|
||||
/>
|
||||
);
|
||||
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")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("<FilterInputLabel /> 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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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(
|
||||
<MainModal alertStore={alertStore} settingsStore={settingsStore} />
|
||||
);
|
||||
};
|
||||
|
||||
const MountedMainModal = () => {
|
||||
return mount(
|
||||
<MainModal alertStore={alertStore} settingsStore={settingsStore} />
|
||||
);
|
||||
};
|
||||
|
||||
describe("<MainModal />", () => {
|
||||
it("only renders FontAwesomeIcon when modal is not shown", () => {
|
||||
const tree = RenderMainModal();
|
||||
const tree = ShallowMainModal();
|
||||
expect(tree.text()).toBe("<FontAwesomeIcon />");
|
||||
});
|
||||
|
||||
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("<FontAwesomeIcon /><MainModalContent />");
|
||||
});
|
||||
|
||||
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("<MainModal />", () => {
|
||||
});
|
||||
|
||||
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("<FontAwesomeIcon /><MainModalContent />");
|
||||
@@ -50,4 +56,27 @@ describe("<MainModal />", () => {
|
||||
instance.toggle.hide();
|
||||
expect(tree.text()).toBe("<FontAwesomeIcon />");
|
||||
});
|
||||
|
||||
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");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 (
|
||||
<div className="container">
|
||||
<nav className="navbar fixed-top navbar-expand navbar-dark p-1 bg-primary-transparent d-inline-block">
|
||||
<ReactResizeDetector handleHeight onResize={navbarResize} />
|
||||
<ReactResizeDetector handleHeight onResize={NavbarOnResize} />
|
||||
<span className="navbar-brand my-0 mx-2 h1 d-none d-sm-block float-left">
|
||||
{alertStore.info.totalAlerts}
|
||||
<FetchIndicator status={alertStore.status.value.toString()} />
|
||||
@@ -67,4 +67,4 @@ const NavBar = observer(
|
||||
}
|
||||
);
|
||||
|
||||
export { NavBar };
|
||||
export { NavBar, NavbarOnResize };
|
||||
|
||||
@@ -7,7 +7,7 @@ import moment from "moment";
|
||||
import { AlertStore, NewUnappliedFilter } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { NavBar } from ".";
|
||||
import { NavBar, NavbarOnResize } from ".";
|
||||
|
||||
let alertStore;
|
||||
let settingsStore;
|
||||
@@ -76,3 +76,21 @@ describe("<NavBar />", () => {
|
||||
ValidateNavClass(3, "flex-column");
|
||||
});
|
||||
});
|
||||
|
||||
describe("NavbarOnResize()", () => {
|
||||
it("body 'padding-top' style is updated after calling NavbarOnResize()", () => {
|
||||
NavbarOnResize(0, 10);
|
||||
expect(
|
||||
window
|
||||
.getComputedStyle(document.body, null)
|
||||
.getPropertyValue("padding-top")
|
||||
).toBe("14px");
|
||||
|
||||
NavbarOnResize(0, 36);
|
||||
expect(
|
||||
window
|
||||
.getComputedStyle(document.body, null)
|
||||
.getPropertyValue("padding-top")
|
||||
).toBe("40px");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -123,25 +123,25 @@ const TabContentDuration = observer(({ silenceFormStore }) => {
|
||||
<Duration
|
||||
label="days"
|
||||
value={silenceFormStore.data.toDuration.days}
|
||||
onInc={() => silenceFormStore.data.incDuration(60 * 24)}
|
||||
onDec={() => silenceFormStore.data.decDuration(60 * 24)}
|
||||
onInc={() => silenceFormStore.data.incEnd(60 * 24)}
|
||||
onDec={() => silenceFormStore.data.decEnd(60 * 24)}
|
||||
/>
|
||||
<Duration
|
||||
label="hours"
|
||||
value={silenceFormStore.data.toDuration.hours}
|
||||
onInc={() => silenceFormStore.data.incDuration(60)}
|
||||
onDec={() => silenceFormStore.data.decDuration(60)}
|
||||
onInc={() => silenceFormStore.data.incEnd(60)}
|
||||
onDec={() => silenceFormStore.data.decEnd(60)}
|
||||
/>
|
||||
<Duration
|
||||
label="minutes"
|
||||
value={silenceFormStore.data.toDuration.minutes}
|
||||
onInc={() =>
|
||||
silenceFormStore.data.incDuration(
|
||||
silenceFormStore.data.incEnd(
|
||||
CalculateChangeValue(silenceFormStore.data.toDuration.minutes, 5)
|
||||
)
|
||||
}
|
||||
onDec={() =>
|
||||
silenceFormStore.data.decDuration(
|
||||
silenceFormStore.data.decEnd(
|
||||
CalculateChangeValue(silenceFormStore.data.toDuration.minutes, 5)
|
||||
)
|
||||
}
|
||||
|
||||
89
ui/src/Components/SilenceModal/LabelNameInput.test.js
Normal file
89
ui/src/Components/SilenceModal/LabelNameInput.test.js
Normal file
@@ -0,0 +1,89 @@
|
||||
import React from "react";
|
||||
|
||||
import { shallow, mount } from "enzyme";
|
||||
|
||||
import { NewEmptyMatcher, MatcherValueToObject } from "Stores/SilenceFormStore";
|
||||
import { LabelNameInput } from "./LabelNameInput";
|
||||
|
||||
let matcher;
|
||||
|
||||
beforeEach(() => {
|
||||
matcher = NewEmptyMatcher();
|
||||
matcher.name = "name";
|
||||
matcher.suggestions.names = [
|
||||
MatcherValueToObject("job"),
|
||||
MatcherValueToObject("cluster")
|
||||
];
|
||||
matcher.suggestions.values = [
|
||||
MatcherValueToObject("foo"),
|
||||
MatcherValueToObject("bar")
|
||||
];
|
||||
});
|
||||
|
||||
const ShallowLabelNameInput = () => {
|
||||
return shallow(<LabelNameInput matcher={matcher} />);
|
||||
};
|
||||
|
||||
const MountedLabelNameInput = () => {
|
||||
return mount(<LabelNameInput matcher={matcher} />);
|
||||
};
|
||||
|
||||
const ValidateSuggestions = () => {
|
||||
const tree = MountedLabelNameInput();
|
||||
// click on the react-select component doesn't seem to trigger options
|
||||
// rendering in tests, so change the input instead
|
||||
tree.find("input").simulate("change", { target: { value: "f" } });
|
||||
return tree;
|
||||
};
|
||||
|
||||
describe("<LabelNameInput />", () => {
|
||||
it("matches snapshot", () => {
|
||||
const tree = ShallowLabelNameInput();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders suggestions", () => {
|
||||
const tree = ValidateSuggestions();
|
||||
const options = tree.find("[role='option']");
|
||||
expect(options).toHaveLength(2);
|
||||
expect(options.at(0).text()).toBe("job");
|
||||
expect(options.at(1).text()).toBe("cluster");
|
||||
});
|
||||
|
||||
it("clicking on options updates the matcher", () => {
|
||||
const tree = ValidateSuggestions();
|
||||
const option = tree.find("[role='option']").at(0);
|
||||
option.simulate("click");
|
||||
expect(matcher.name).toBe("job");
|
||||
});
|
||||
|
||||
it("populates suggestions on mount", done => {
|
||||
fetch
|
||||
.once(JSON.stringify(["name1", "name2", "name3"]))
|
||||
.once(JSON.stringify(["value1", "value2", "value3"]));
|
||||
ShallowLabelNameInput();
|
||||
// use timeout since mount will call fetch
|
||||
setTimeout(() => {
|
||||
expect(matcher.suggestions.names).toHaveLength(3);
|
||||
for (let i = 0; i < 3; i++) {
|
||||
expect(matcher.suggestions.names[i]).toMatchObject(
|
||||
MatcherValueToObject(`name${i + 1}`)
|
||||
);
|
||||
expect(matcher.suggestions.values[i]).toMatchObject(
|
||||
MatcherValueToObject(`value${i + 1}`)
|
||||
);
|
||||
}
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it("suggestions are empited on failed fetch", done => {
|
||||
fetch.mockReject(new Error("fake error message"));
|
||||
ShallowLabelNameInput();
|
||||
// use timeout since mount will call fetch
|
||||
setTimeout(() => {
|
||||
expect(matcher.suggestions.names).toHaveLength(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
88
ui/src/Components/SilenceModal/LabelValueInput.test.js
Normal file
88
ui/src/Components/SilenceModal/LabelValueInput.test.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import React from "react";
|
||||
|
||||
import { shallow, mount } from "enzyme";
|
||||
|
||||
import { NewEmptyMatcher, MatcherValueToObject } from "Stores/SilenceFormStore";
|
||||
import { LabelValueInput } from "./LabelValueInput";
|
||||
|
||||
let matcher;
|
||||
|
||||
beforeEach(() => {
|
||||
matcher = NewEmptyMatcher();
|
||||
matcher.name = "name";
|
||||
matcher.suggestions.names = [
|
||||
MatcherValueToObject("job"),
|
||||
MatcherValueToObject("cluster")
|
||||
];
|
||||
matcher.suggestions.values = [
|
||||
MatcherValueToObject("foo"),
|
||||
MatcherValueToObject("bar")
|
||||
];
|
||||
});
|
||||
|
||||
const ShallowLabelValueInput = () => {
|
||||
return shallow(<LabelValueInput matcher={matcher} />);
|
||||
};
|
||||
|
||||
const MountedLabelValueInput = () => {
|
||||
return mount(<LabelValueInput matcher={matcher} />);
|
||||
};
|
||||
|
||||
const ValidateSuggestions = () => {
|
||||
const tree = MountedLabelValueInput();
|
||||
// click on the react-select component doesn't seem to trigger options
|
||||
// rendering in tests, so change the input instead
|
||||
tree.find("input").simulate("change", { target: { value: "f" } });
|
||||
return tree;
|
||||
};
|
||||
|
||||
describe("<LabelValueInput />", () => {
|
||||
it("matches snapshot", () => {
|
||||
const tree = ShallowLabelValueInput();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders suggestions", () => {
|
||||
const tree = ValidateSuggestions();
|
||||
const options = tree.find("[role='option']");
|
||||
expect(options).toHaveLength(2);
|
||||
expect(options.at(0).text()).toBe("foo");
|
||||
expect(options.at(1).text()).toBe("bar");
|
||||
});
|
||||
|
||||
it("clicking on options appends them to matcher.values", () => {
|
||||
const tree = ValidateSuggestions();
|
||||
const options = tree.find("[role='option']");
|
||||
options.at(0).simulate("click");
|
||||
options.at(1).simulate("click");
|
||||
expect(matcher.values).toHaveLength(2);
|
||||
expect(matcher.values).toContainEqual(MatcherValueToObject("foo"));
|
||||
expect(matcher.values).toContainEqual(MatcherValueToObject("bar"));
|
||||
});
|
||||
|
||||
it("selecting one option doesn't force matcher.isRegex=true", () => {
|
||||
const tree = ValidateSuggestions();
|
||||
expect(matcher.isRegex).toBe(false);
|
||||
const options = tree.find("[role='option']");
|
||||
options.at(0).simulate("click");
|
||||
expect(matcher.isRegex).toBe(false);
|
||||
});
|
||||
|
||||
it("selecting one option when matcher.isRegex=true changes it back to false", () => {
|
||||
matcher.isRegex = true;
|
||||
const tree = ValidateSuggestions();
|
||||
expect(matcher.isRegex).toBe(true);
|
||||
const options = tree.find("[role='option']");
|
||||
options.at(0).simulate("click");
|
||||
expect(matcher.isRegex).toBe(false);
|
||||
});
|
||||
|
||||
it("selecting multiple options forces matcher.isRegex=true", () => {
|
||||
const tree = ValidateSuggestions();
|
||||
expect(matcher.isRegex).toBe(false);
|
||||
const options = tree.find("[role='option']");
|
||||
options.at(0).simulate("click");
|
||||
options.at(1).simulate("click");
|
||||
expect(matcher.isRegex).toBe(true);
|
||||
});
|
||||
});
|
||||
129
ui/src/Components/SilenceModal/SilenceForm.test.js
Normal file
129
ui/src/Components/SilenceModal/SilenceForm.test.js
Normal file
@@ -0,0 +1,129 @@
|
||||
import React from "react";
|
||||
|
||||
import { mount, shallow } from "enzyme";
|
||||
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { SilenceForm } from "./SilenceForm";
|
||||
|
||||
let alertStore;
|
||||
let silenceFormStore;
|
||||
|
||||
beforeEach(() => {
|
||||
alertStore = new AlertStore([]);
|
||||
silenceFormStore = new SilenceFormStore();
|
||||
});
|
||||
|
||||
const ShallowSilenceForm = () => {
|
||||
return shallow(
|
||||
<SilenceForm alertStore={alertStore} silenceFormStore={silenceFormStore} />
|
||||
);
|
||||
};
|
||||
|
||||
const MountedSilenceForm = () => {
|
||||
return mount(
|
||||
<SilenceForm alertStore={alertStore} silenceFormStore={silenceFormStore} />
|
||||
);
|
||||
};
|
||||
|
||||
describe("<SilenceForm /> matchers", () => {
|
||||
it("has an empty matcher selects on default render", () => {
|
||||
const tree = ShallowSilenceForm();
|
||||
const matchers = tree.find("SilenceMatch");
|
||||
expect(matchers).toHaveLength(1);
|
||||
expect(silenceFormStore.data.matchers).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("clicking 'Add more' button adds another matcher", () => {
|
||||
const tree = ShallowSilenceForm();
|
||||
const button = tree.find("button[type='button']");
|
||||
button.simulate("click", { preventDefault: jest.fn() });
|
||||
const matchers = tree.find("SilenceMatch");
|
||||
expect(matchers).toHaveLength(2);
|
||||
expect(silenceFormStore.data.matchers).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("trash icon is not visible when there's only one matcher", () => {
|
||||
const tree = MountedSilenceForm();
|
||||
expect(silenceFormStore.data.matchers).toHaveLength(1);
|
||||
|
||||
const matcher = tree.find("SilenceMatch");
|
||||
const button = matcher.find("button");
|
||||
expect(button).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("trash icon is visible when there are two matchers", () => {
|
||||
silenceFormStore.data.addEmptyMatcher();
|
||||
silenceFormStore.data.addEmptyMatcher();
|
||||
const tree = MountedSilenceForm();
|
||||
expect(silenceFormStore.data.matchers).toHaveLength(2);
|
||||
|
||||
const matcher = tree.find("SilenceMatch");
|
||||
const button = matcher.find("button");
|
||||
expect(button).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("clicking trash icon on a matcher select removes it", () => {
|
||||
silenceFormStore.data.addEmptyMatcher();
|
||||
silenceFormStore.data.addEmptyMatcher();
|
||||
silenceFormStore.data.addEmptyMatcher();
|
||||
const tree = MountedSilenceForm();
|
||||
expect(silenceFormStore.data.matchers).toHaveLength(3);
|
||||
|
||||
const matchers = tree.find("SilenceMatch");
|
||||
const toDelete = matchers.at(1);
|
||||
const button = toDelete.find("button");
|
||||
button.simulate("click");
|
||||
expect(silenceFormStore.data.matchers).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("<SilenceForm /> preview", () => {
|
||||
it("doesn't render SilencePreview when previewCollapse.hidden is true", () => {
|
||||
const tree = ShallowSilenceForm();
|
||||
const instance = tree.instance();
|
||||
instance.previewCollapse.hidden = true;
|
||||
expect(tree.find("SilencePreview")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("renders SilencePreview when previewCollapse.hidden is false", () => {
|
||||
const tree = ShallowSilenceForm();
|
||||
const instance = tree.instance();
|
||||
instance.previewCollapse.hidden = false;
|
||||
expect(tree.find("SilencePreview")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("clicking on the toggle icon toggles SilencePreview", () => {
|
||||
const tree = ShallowSilenceForm();
|
||||
const button = tree.find("a.btn.cursor-pointer.text-muted");
|
||||
expect(tree.find("SilencePreview")).toHaveLength(0);
|
||||
button.simulate("click");
|
||||
expect(tree.find("SilencePreview")).toHaveLength(1);
|
||||
button.simulate("click");
|
||||
expect(tree.find("SilencePreview")).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("<SilenceForm /> inputs", () => {
|
||||
it("changing author input updates SilenceFormStore", () => {
|
||||
const tree = MountedSilenceForm();
|
||||
const input = tree.find("input[placeholder='Author email']");
|
||||
input.simulate("change", { target: { value: "me@example.com" } });
|
||||
expect(silenceFormStore.data.author).toBe("me@example.com");
|
||||
});
|
||||
|
||||
it("changing comment input updates SilenceFormStore", () => {
|
||||
const tree = MountedSilenceForm();
|
||||
const input = tree.find("input[placeholder='Comment']");
|
||||
input.simulate("change", { target: { value: "fake comment" } });
|
||||
expect(silenceFormStore.data.comment).toBe("fake comment");
|
||||
});
|
||||
});
|
||||
|
||||
describe("<SilenceForm />", () => {
|
||||
it("calling submit marks form as in progress", () => {
|
||||
const tree = ShallowSilenceForm();
|
||||
tree.simulate("submit", { preventDefault: jest.fn() });
|
||||
expect(silenceFormStore.data.inProgress).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -25,7 +25,6 @@ const SilenceMatch = observer(
|
||||
|
||||
onIsRegexChange = action(event => {
|
||||
const { matcher } = this.props;
|
||||
console.info(matcher.values);
|
||||
|
||||
// only allow to change value if we don't have multiple values
|
||||
if (matcher.values.length <= 1) {
|
||||
|
||||
37
ui/src/Components/SilenceModal/SilenceMatch.test.js
Normal file
37
ui/src/Components/SilenceModal/SilenceMatch.test.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from "react";
|
||||
|
||||
import { shallow } from "enzyme";
|
||||
|
||||
import { NewEmptyMatcher, MatcherValueToObject } from "Stores/SilenceFormStore";
|
||||
import { SilenceMatch } from "./SilenceMatch";
|
||||
|
||||
let matcher;
|
||||
|
||||
beforeEach(() => {
|
||||
matcher = NewEmptyMatcher();
|
||||
});
|
||||
|
||||
const ShallowLabelValueInput = () => {
|
||||
return shallow(<SilenceMatch matcher={matcher} />);
|
||||
};
|
||||
|
||||
describe("<SilenceMatch />", () => {
|
||||
it("allows changing matcher.isRegex value when matcher.values contains 1 element", () => {
|
||||
matcher.values = [MatcherValueToObject("foo")];
|
||||
const tree = ShallowLabelValueInput();
|
||||
expect(matcher.isRegex).toBe(false);
|
||||
const regex = tree.find("input[type='checkbox']");
|
||||
regex.simulate("change", { target: { checked: true } });
|
||||
expect(matcher.isRegex).toBe(true);
|
||||
});
|
||||
|
||||
it("disallows changing matcher.isRegex value when matcher.values contains 2 elements", () => {
|
||||
matcher.isRegex = true;
|
||||
matcher.values = [MatcherValueToObject("foo"), MatcherValueToObject("bar")];
|
||||
const tree = ShallowLabelValueInput();
|
||||
expect(matcher.isRegex).toBe(true);
|
||||
const regex = tree.find("input[type='checkbox']");
|
||||
regex.simulate("change", { target: { checked: false } });
|
||||
expect(matcher.isRegex).toBe(true);
|
||||
});
|
||||
});
|
||||
40
ui/src/Components/SilenceModal/SilenceModalContent.test.js
Normal file
40
ui/src/Components/SilenceModal/SilenceModalContent.test.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import React from "react";
|
||||
|
||||
import { shallow } from "enzyme";
|
||||
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { SilenceModalContent } from "./SilenceModalContent";
|
||||
|
||||
let alertStore;
|
||||
let silenceFormStore;
|
||||
|
||||
beforeEach(() => {
|
||||
alertStore = new AlertStore([]);
|
||||
silenceFormStore = new SilenceFormStore();
|
||||
});
|
||||
|
||||
const ShallowSilenceModalContent = () => {
|
||||
return shallow(
|
||||
<SilenceModalContent
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
describe("<SilenceModalContent />", () => {
|
||||
it("renders SilenceForm when silenceFormStore.data.inProgress is false", () => {
|
||||
silenceFormStore.data.inProgress = false;
|
||||
const tree = ShallowSilenceModalContent();
|
||||
const form = tree.find("SilenceForm");
|
||||
expect(form).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("renders SilenceSubmitController when silenceFormStore.data.inProgress is true", () => {
|
||||
silenceFormStore.data.inProgress = true;
|
||||
const tree = ShallowSilenceModalContent();
|
||||
const ctrl = tree.find("SilenceSubmitController");
|
||||
expect(ctrl).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
21
ui/src/Components/SilenceModal/SilencePreview.test.js
Normal file
21
ui/src/Components/SilenceModal/SilencePreview.test.js
Normal file
@@ -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("<SilencePreview />", () => {
|
||||
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(<SilencePreview silenceFormStore={silenceFormStore} />);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import React from "react";
|
||||
|
||||
import { shallow } from "enzyme";
|
||||
|
||||
import {
|
||||
SilenceFormStore,
|
||||
MatcherValueToObject
|
||||
} from "Stores/SilenceFormStore";
|
||||
import { SilenceSubmitController } from "./SilenceSubmitController";
|
||||
|
||||
let silenceFormStore;
|
||||
|
||||
beforeEach(() => {
|
||||
silenceFormStore = new SilenceFormStore();
|
||||
});
|
||||
|
||||
const ShallowSilenceSubmitController = () => {
|
||||
return shallow(
|
||||
<SilenceSubmitController silenceFormStore={silenceFormStore} />
|
||||
);
|
||||
};
|
||||
|
||||
describe("<SilenceSubmitController />", () => {
|
||||
it("renders all passed SilenceSubmitProgress", () => {
|
||||
silenceFormStore.data.alertmanagers.push(MatcherValueToObject("am1"));
|
||||
silenceFormStore.data.alertmanagers.push(MatcherValueToObject("am2"));
|
||||
const tree = ShallowSilenceSubmitController();
|
||||
const alertmanagers = tree.find("SilenceSubmitProgress");
|
||||
expect(alertmanagers).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("resets the form on 'Back' button click", () => {
|
||||
silenceFormStore.data.inProgress = true;
|
||||
const tree = ShallowSilenceSubmitController();
|
||||
const button = tree.find("button");
|
||||
button.simulate("click");
|
||||
expect(silenceFormStore.data.inProgress).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<LabelNameInput /> matches snapshot 1`] = `
|
||||
<StateManager
|
||||
defaultInputValue=""
|
||||
defaultMenuIsOpen={false}
|
||||
defaultValue={
|
||||
Object {
|
||||
"label": "name",
|
||||
"value": "name",
|
||||
}
|
||||
}
|
||||
instanceId="silence-input-label-name-1"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"label": "job",
|
||||
"value": "job",
|
||||
},
|
||||
Object {
|
||||
"label": "cluster",
|
||||
"value": "cluster",
|
||||
},
|
||||
]
|
||||
}
|
||||
placeholder="Label name"
|
||||
styles={
|
||||
Object {
|
||||
"control": [Function],
|
||||
"indicatorsContainer": [Function],
|
||||
"multiValue": [Function],
|
||||
"multiValueLabel": [Function],
|
||||
"multiValueRemove": [Function],
|
||||
"option": [Function],
|
||||
"valueContainer": [Function],
|
||||
"valueLabel": [Function],
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
||||
@@ -0,0 +1,37 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<LabelValueInput /> matches snapshot 1`] = `
|
||||
<StateManager
|
||||
defaultInputValue=""
|
||||
defaultMenuIsOpen={false}
|
||||
defaultValue={Array []}
|
||||
instanceId="silence-input-label-value-1"
|
||||
isMulti={true}
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"label": "foo",
|
||||
"value": "foo",
|
||||
},
|
||||
Object {
|
||||
"label": "bar",
|
||||
"value": "bar",
|
||||
},
|
||||
]
|
||||
}
|
||||
placeholder="Label value"
|
||||
styles={
|
||||
Object {
|
||||
"control": [Function],
|
||||
"indicatorsContainer": [Function],
|
||||
"multiValue": [Function],
|
||||
"multiValueLabel": [Function],
|
||||
"multiValueRemove": [Function],
|
||||
"option": [Function],
|
||||
"valueContainer": [Function],
|
||||
"valueLabel": [Function],
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
||||
@@ -0,0 +1,73 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<SilencePreview /> matches snapshot 1`] = `
|
||||
<div
|
||||
class="mt-3"
|
||||
>
|
||||
<pre
|
||||
class="json-pretty"
|
||||
>
|
||||
{
|
||||
"
|
||||
<span
|
||||
class="json-key"
|
||||
>
|
||||
matchers
|
||||
</span>
|
||||
": [],
|
||||
"
|
||||
<span
|
||||
class="json-key"
|
||||
>
|
||||
startsAt
|
||||
</span>
|
||||
":
|
||||
<span
|
||||
class="json-string"
|
||||
>
|
||||
"2000-02-01T00:00:00.000Z"
|
||||
</span>
|
||||
,
|
||||
"
|
||||
<span
|
||||
class="json-key"
|
||||
>
|
||||
endsAt
|
||||
</span>
|
||||
":
|
||||
<span
|
||||
class="json-string"
|
||||
>
|
||||
"2000-02-01T01:00:00.000Z"
|
||||
</span>
|
||||
,
|
||||
"
|
||||
<span
|
||||
class="json-key"
|
||||
>
|
||||
createdBy
|
||||
</span>
|
||||
":
|
||||
<span
|
||||
class="json-string"
|
||||
>
|
||||
""
|
||||
</span>
|
||||
,
|
||||
"
|
||||
<span
|
||||
class="json-key"
|
||||
>
|
||||
comment
|
||||
</span>
|
||||
":
|
||||
<span
|
||||
class="json-string"
|
||||
>
|
||||
"SilencePreview test"
|
||||
</span>
|
||||
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
`;
|
||||
81
ui/src/Components/SilenceModal/index.test.js
Normal file
81
ui/src/Components/SilenceModal/index.test.js
Normal file
@@ -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(
|
||||
<SilenceModal alertStore={alertStore} silenceFormStore={silenceFormStore} />
|
||||
);
|
||||
};
|
||||
|
||||
const MountedSilenceModal = () => {
|
||||
return mount(
|
||||
<SilenceModal alertStore={alertStore} silenceFormStore={silenceFormStore} />
|
||||
);
|
||||
};
|
||||
|
||||
describe("<SilenceModal />", () => {
|
||||
it("only renders FontAwesomeIcon when modal is not shown", () => {
|
||||
const tree = ShallowSilenceModal();
|
||||
expect(tree.text()).toBe("<FontAwesomeIcon />");
|
||||
});
|
||||
|
||||
it("renders the modal when it is shown", () => {
|
||||
const tree = ShallowSilenceModal();
|
||||
const toggle = tree.find(".nav-link");
|
||||
toggle.simulate("click");
|
||||
expect(tree.text()).toBe("<FontAwesomeIcon /><SilenceModalContent />");
|
||||
});
|
||||
|
||||
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("<FontAwesomeIcon />");
|
||||
});
|
||||
|
||||
it("hides the modal when hide() is called", () => {
|
||||
const tree = ShallowSilenceModal();
|
||||
const toggle = tree.find(".nav-link");
|
||||
toggle.simulate("click");
|
||||
expect(tree.text()).toBe("<FontAwesomeIcon /><SilenceModalContent />");
|
||||
silenceFormStore.toggle.hide();
|
||||
expect(tree.text()).toBe("<FontAwesomeIcon />");
|
||||
});
|
||||
|
||||
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");
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,7 @@ import uniqueId from "lodash.uniqueid";
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
const NewEmptyMatcher = id => {
|
||||
const NewEmptyMatcher = () => {
|
||||
return {
|
||||
id: uniqueId(),
|
||||
name: "",
|
||||
@@ -17,7 +17,7 @@ const NewEmptyMatcher = id => {
|
||||
};
|
||||
};
|
||||
|
||||
const ValueToObject = value => ({ label: value, value: value });
|
||||
const MatcherValueToObject = value => ({ label: value, value: value });
|
||||
|
||||
class SilenceFormStore {
|
||||
// this is used to store modal visibility toggle
|
||||
@@ -75,16 +75,10 @@ class SilenceFormStore {
|
||||
for (const [key, value] of Object.entries(
|
||||
Object.assign({}, group.labels, group.shared.labels)
|
||||
)) {
|
||||
matchers.push({
|
||||
id: uniqueId(),
|
||||
name: key,
|
||||
values: [ValueToObject(value)],
|
||||
suggestions: {
|
||||
names: [],
|
||||
values: []
|
||||
},
|
||||
isRegex: false
|
||||
});
|
||||
const matcher = NewEmptyMatcher();
|
||||
matcher.name = key;
|
||||
matcher.values = [MatcherValueToObject(value)];
|
||||
matchers.push(matcher);
|
||||
}
|
||||
|
||||
// add matchers for all unique labels in this group
|
||||
@@ -101,7 +95,9 @@ class SilenceFormStore {
|
||||
matchers.push({
|
||||
id: uniqueId(),
|
||||
name: key,
|
||||
values: [...values].sort().map(value => ValueToObject(value)),
|
||||
values: [...values]
|
||||
.sort()
|
||||
.map(value => MatcherValueToObject(value)),
|
||||
suggestions: {
|
||||
names: [],
|
||||
values: []
|
||||
@@ -141,15 +137,6 @@ class SilenceFormStore {
|
||||
this.verifyStarEnd();
|
||||
},
|
||||
|
||||
incDuration(minutes) {
|
||||
this.endsAt = moment(this.endsAt).add(minutes, "minutes");
|
||||
this.verifyStarEnd();
|
||||
},
|
||||
decDuration(minutes) {
|
||||
this.endsAt = moment(this.endsAt).subtract(minutes, "minutes");
|
||||
this.verifyStarEnd();
|
||||
},
|
||||
|
||||
get toAlertmanagerPayload() {
|
||||
const payload = {
|
||||
matchers: this.matchers.map(m => ({
|
||||
@@ -194,8 +181,6 @@ class SilenceFormStore {
|
||||
decStart: action.bound,
|
||||
incEnd: action.bound,
|
||||
decEnd: action.bound,
|
||||
incDuration: action.bound,
|
||||
decDuration: action.bound,
|
||||
toAlertmanagerPayload: computed,
|
||||
toDuration: computed
|
||||
},
|
||||
@@ -203,4 +188,4 @@ class SilenceFormStore {
|
||||
);
|
||||
}
|
||||
|
||||
export { SilenceFormStore };
|
||||
export { SilenceFormStore, NewEmptyMatcher, MatcherValueToObject };
|
||||
|
||||
@@ -114,6 +114,8 @@ describe("SilenceFormStore.data", () => {
|
||||
it("toAlertmanagerPayload creates payload that matches snapshot", () => {
|
||||
const group = MockGroup();
|
||||
store.data.fillMatchersFromGroup(group);
|
||||
// add empty matcher so we test empty string rendering
|
||||
store.data.addEmptyMatcher();
|
||||
store.data.startsAt = moment([2000, 1, 1, 0, 0, 0]);
|
||||
store.data.endsAt = moment([2000, 1, 1, 1, 0, 0]);
|
||||
store.data.createdBy = "me@example.com";
|
||||
@@ -121,3 +123,100 @@ describe("SilenceFormStore.data", () => {
|
||||
expect(store.data.toAlertmanagerPayload).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("SilenceFormStore.data startsAt & endsAt validation", () => {
|
||||
it("toDuration returns correct duration for 5d 0h 1m", () => {
|
||||
store.data.startsAt = moment([2000, 1, 1, 0, 0, 0]);
|
||||
store.data.endsAt = moment([2000, 1, 6, 0, 1, 15]);
|
||||
expect(store.data.toDuration).toMatchObject({
|
||||
days: 5,
|
||||
hours: 0,
|
||||
minutes: 1
|
||||
});
|
||||
});
|
||||
|
||||
it("toDuration returns correct duration for 2h 15m", () => {
|
||||
store.data.startsAt = moment([2000, 1, 1, 0, 0, 0]);
|
||||
store.data.endsAt = moment([2000, 1, 1, 2, 15, 0]);
|
||||
expect(store.data.toDuration).toMatchObject({
|
||||
days: 0,
|
||||
hours: 2,
|
||||
minutes: 15
|
||||
});
|
||||
});
|
||||
|
||||
it("toDuration returns correct duration for 59m", () => {
|
||||
store.data.startsAt = moment([2000, 1, 1, 0, 10, 0]);
|
||||
store.data.endsAt = moment([2000, 1, 1, 1, 9, 0]);
|
||||
expect(store.data.toDuration).toMatchObject({
|
||||
days: 0,
|
||||
hours: 0,
|
||||
minutes: 59
|
||||
});
|
||||
});
|
||||
|
||||
it("verifyStarEnd() doesn't do anything if endsAt if after startsAt", () => {
|
||||
const startsAt = moment([2063, 1, 1, 0, 0, 0]);
|
||||
const endsAt = moment([2063, 1, 1, 1, 1, 0]);
|
||||
store.data.startsAt = startsAt;
|
||||
store.data.endsAt = endsAt;
|
||||
store.data.verifyStarEnd();
|
||||
expect(store.data.startsAt.toISOString()).toBe(startsAt.toISOString());
|
||||
expect(store.data.endsAt.toISOString()).toBe(endsAt.toISOString());
|
||||
});
|
||||
|
||||
it("verifyStarEnd() updates startsAt if it's before now()", () => {
|
||||
const now = moment().second(0);
|
||||
const startsAt = moment([2000, 1, 1, 0, 0, 1]);
|
||||
const endsAt = moment([2063, 1, 1, 0, 0, 0]);
|
||||
store.data.startsAt = startsAt;
|
||||
store.data.endsAt = endsAt;
|
||||
store.data.verifyStarEnd();
|
||||
expect(store.data.startsAt.isSameOrAfter(now)).toBeTruthy();
|
||||
expect(store.data.endsAt.toISOString()).toBe(endsAt.toISOString());
|
||||
});
|
||||
|
||||
it("verifyStarEnd() updates endsAt if it's before startsAt", () => {
|
||||
const startsAt = moment([2063, 1, 1, 0, 0, 1]);
|
||||
const endsAt = moment([2063, 1, 1, 0, 0, 0]);
|
||||
store.data.startsAt = startsAt;
|
||||
store.data.endsAt = endsAt;
|
||||
store.data.verifyStarEnd();
|
||||
expect(store.data.startsAt.toISOString()).toBe(startsAt.toISOString());
|
||||
expect(store.data.endsAt.toISOString()).toBe(
|
||||
moment([2063, 1, 1, 0, 1, 1]).toISOString()
|
||||
);
|
||||
});
|
||||
|
||||
it("incStart(7) adds 7 minutes to startsAt", () => {
|
||||
const startsAt = moment([2063, 1, 1, 0, 0, 1]);
|
||||
store.data.startsAt = startsAt;
|
||||
store.data.incStart(7);
|
||||
const diffMS = store.data.startsAt.diff(startsAt);
|
||||
expect(diffMS).toBe(7 * 60 * 1000);
|
||||
});
|
||||
|
||||
it("decStart(14) subtracts 14 minutes from startsAt", () => {
|
||||
const startsAt = moment([2063, 1, 1, 0, 0, 1]);
|
||||
store.data.startsAt = startsAt;
|
||||
store.data.decStart(14);
|
||||
const diffMS = store.data.startsAt.diff(startsAt);
|
||||
expect(diffMS).toBe(-14 * 60 * 1000);
|
||||
});
|
||||
|
||||
it("incEnd(120) adds 120 minutes to endsAt", () => {
|
||||
const endsAt = moment([2063, 1, 1, 0, 0, 1]);
|
||||
store.data.endsAt = endsAt;
|
||||
store.data.incEnd(120);
|
||||
const diffMS = store.data.endsAt.diff(endsAt);
|
||||
expect(diffMS).toBe(120 * 60 * 1000);
|
||||
});
|
||||
|
||||
it("decEnd(1) subtracts 1 minute from endsAt", () => {
|
||||
const endsAt = moment([2063, 1, 1, 0, 0, 1]);
|
||||
store.data.endsAt = endsAt;
|
||||
store.data.decEnd(1);
|
||||
const diffMS = store.data.endsAt.diff(endsAt);
|
||||
expect(diffMS).toBe(-1 * 60 * 1000);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,6 +26,11 @@ Object {
|
||||
"name": "cluster",
|
||||
"value": "(dev|prod)",
|
||||
},
|
||||
Object {
|
||||
"isRegex": false,
|
||||
"name": "",
|
||||
"value": "",
|
||||
},
|
||||
],
|
||||
"startsAt": "2000-02-01T00:00:00.000Z",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user