import React from "react"; import { act } from "react-dom/test-utils"; import { mount, shallow } from "enzyme"; import { advanceTo, clear } from "jest-date-mock"; import toDiffableHtml from "diffable-html"; import moment from "moment"; import { SilenceFormStore } from "Stores/SilenceFormStore"; import { DateTimeSelect, TabContentStart, TabContentEnd, TabContentDuration, } from "."; let silenceFormStore; beforeEach(() => { silenceFormStore = new SilenceFormStore(); silenceFormStore.data.startsAt = moment([2060, 1, 1, 0, 0, 0]); silenceFormStore.data.endsAt = moment([2061, 1, 1, 0, 0, 0]); }); afterEach(() => { clear(); }); const ShallowDateTimeSelect = () => { return shallow(); }; const MountedDateTimeSelect = () => { return mount(); }; describe("", () => { it("renders 3 tabs", () => { const tree = ShallowDateTimeSelect(); const tabs = tree.find("Tab"); expect(tabs).toHaveLength(3); }); it("renders 'Duration' tab by default", () => { const tree = MountedDateTimeSelect(); const tab = tree.find(".nav-link.active"); expect(tab).toHaveLength(1); // check tab title expect(tab.text()).toMatch(/Duration/); // check tab content expect(tree.find(".tab-content").text()).toBe("366days0hours0minutes"); }); it("'Duration' tab matches snapshot", () => { advanceTo(new Date(2060, 1, 1, 0, 0, 0)); const tree = MountedDateTimeSelect(); expect(toDiffableHtml(tree.html())).toMatchSnapshot(); }); it("'Duration' tab unmounts without crashing", () => { const tree = MountedDateTimeSelect(); tree.unmount(); }); it("clicking on the 'Starts' tab switches content to 'startsAt' selection", () => { const tree = MountedDateTimeSelect(); const tab = tree.find(".nav-link").at(0); expect(tab.text()).toMatch(/Starts/); tab.simulate("click"); expect(tree.find(".tab-content").text()).toMatch(/2060/); }); it("'Starts' tab matches snapshot", () => { advanceTo(new Date(2060, 1, 1, 0, 0, 0)); const tree = MountedDateTimeSelect(); tree.find(".nav-link").at(0).simulate("click"); expect(toDiffableHtml(tree.html())).toMatchSnapshot(); }); it("'Starts' tab unmounts without crashing", () => { const tree = MountedDateTimeSelect(); tree.find(".nav-link").at(0).simulate("click"); tree.unmount(); }); it("clicking on the 'Ends' tab switches content to 'endsAt' selection", () => { const tree = MountedDateTimeSelect(); const tab = tree.find(".nav-link").at(1); expect(tab.text()).toMatch(/Ends/); tab.simulate("click"); expect(tree.find(".tab-content").text()).toMatch(/2061/); }); it("'Ends' tab matches snapshot", () => { advanceTo(new Date(2060, 1, 1, 0, 0, 0)); const tree = MountedDateTimeSelect(); tree.find(".nav-link").at(1).simulate("click"); expect(toDiffableHtml(tree.html())).toMatchSnapshot(); }); it("'Ends' tab unmounts without crashing", () => { const tree = MountedDateTimeSelect(); tree.find(".nav-link").at(1).simulate("click"); tree.unmount(); }); it("clicking on the 'Duration' tabs switches content to duration selection", () => { const tree = MountedDateTimeSelect(); // first switch to 'Starts' tree.find(".nav-link").at(0).simulate("click"); // then switch back to 'Duration' const tab = tree.find(".nav-link").at(2); expect(tab.text()).toMatch(/Duration/); tab.simulate("click"); expect(tree.find(".tab-content").text()).toBe("366days0hours0minutes"); }); it("'Ends' tab offset badge is updated after 1 minute", () => { jest.useFakeTimers(); advanceTo(new Date(2060, 1, 1, 12, 0, 0)); silenceFormStore.data.startsAt = moment([2060, 1, 1, 12, 0, 0]); silenceFormStore.data.endsAt = moment([2060, 1, 1, 13, 0, 0]); const tree = MountedDateTimeSelect(); expect(tree.find(".nav-link").at(1).text()).toBe("Endsin 1h "); advanceTo(new Date(2060, 1, 1, 12, 1, 0)); act(() => jest.runOnlyPendingTimers()); expect(tree.find(".nav-link").at(1).text()).toBe("Endsin 59m "); }); it("unmounts cleanly", () => { const tree = MountedDateTimeSelect(); tree.unmount(); }); }); const ValidateTimeButton = ( tab, storeKey, elemIndex, iconMatch, expectedDiff ) => { const button = tab.find("td > span").at(elemIndex); expect(button.html()).toMatch(iconMatch); const oldTimeValue = moment(silenceFormStore.data[storeKey]); button.simulate("click"); expect(silenceFormStore.data[storeKey].toISOString()).not.toBe( oldTimeValue.toISOString() ); const diffMS = silenceFormStore.data[storeKey].diff(oldTimeValue); expect(diffMS).toBe(expectedDiff); }; const ValidateTimeWheel = (tab, storeKey, className, deltaY, expectedDiff) => { const elem = tab.find(className); const oldTimeValue = moment(silenceFormStore.data[storeKey]); elem.simulate("wheel", { deltaY: deltaY }); // fire real event so cancel listener will trigger const event = new Event("wheel", { deltaY: deltaY }); tab .find("div.components-hour-minute") .at(0) .getDOMNode() .dispatchEvent(event); expect(silenceFormStore.data[storeKey].toISOString()).not.toBe( oldTimeValue.toISOString() ); const diffMS = silenceFormStore.data[storeKey].diff(oldTimeValue); expect(diffMS).toBe(expectedDiff); }; const MountedTabContentStart = () => { return mount(); }; describe("", () => { it("selecting date on DatePicker updates startsAt", () => { const tree = MountedTabContentStart(); expect(silenceFormStore.data.startsAt.toISOString()).toBe( moment([2060, 1, 1, 0, 0, 0]).toISOString() ); tree.find("div.react-datepicker__day--018").simulate("click"); expect(silenceFormStore.data.startsAt.toISOString()).toBe( moment([2060, 1, 18, 0, 0, 0]).toISOString() ); }); it("clicking on the hour inc button adds 1h to startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeButton(tree, "startsAt", 0, /angle-up/, 3600 * 1000); }); it("scrolling up on the hour button adds 1h to startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeWheel( tree, "startsAt", "td.components-hour-up", -1, 3600 * 1000 ); }); it("clicking on the minute inc button adds 1m to startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeButton(tree, "startsAt", 1, /angle-up/, 60 * 1000); }); it("scrolling up on the minute button adds 1m to startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeWheel( tree, "startsAt", "td.components-minute-up", -2, 60 * 1000 ); }); it("clicking on the hour dec button subtracts 1h from startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeButton(tree, "startsAt", 2, /angle-down/, -1 * 3600 * 1000); }); it("scrolling down on the hour button subtracts 1h from startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeWheel( tree, "startsAt", "td.components-hour-down", 1, -1 * 3600 * 1000 ); }); it("scrolling up on the minute adds 1m to startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeWheel(tree, "startsAt", "td.components-minute", -2, 60 * 1000); }); it("scrolling down on the minute subtracts 1m from startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeWheel( tree, "startsAt", "td.components-minute", 1, -1 * 60 * 1000 ); }); it("clicking on the minute dec button subtracts 1m from startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeButton(tree, "startsAt", 3, /angle-down/, -1 * 60 * 1000); }); it("scrolling down on the minute button subtracts 1m from startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeWheel( tree, "startsAt", "td.components-minute-down", 2, -1 * 60 * 1000 ); }); it("scrolling up on the minute subtracts 1m from startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeWheel(tree, "startsAt", "td.components-minute", -50, 60 * 1000); }); it("scrolling down on the minute subtracts 1m from startsAt", () => { const tree = MountedTabContentStart(); ValidateTimeWheel( tree, "startsAt", "td.components-minute", 1, -1 * 60 * 1000 ); }); }); const MountedTabContentEnd = () => { return mount(); }; describe("", () => { it("Selecting date on DatePicker updates endsAt", () => { const tree = MountedTabContentEnd(); expect(silenceFormStore.data.endsAt.toISOString()).toBe( moment([2061, 1, 1, 0, 0, 0]).toISOString() ); tree.find("div.react-datepicker__day--024").simulate("click"); expect(silenceFormStore.data.endsAt.toISOString()).toBe( moment([2061, 1, 24, 0, 0, 0]).toISOString() ); }); it("clicking on the hour inc button adds 1h to endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeButton(tree, "endsAt", 0, /angle-up/, 3600 * 1000); }); it("scrolling up on the hour button adds 1h to endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeWheel(tree, "endsAt", "td.components-hour-up", -1, 3600 * 1000); }); it("scrolling up on the hour adds 1h to endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeWheel(tree, "endsAt", "td.components-hour", -1, 3600 * 1000); }); it("scrolling down on the hour subtracts 1h from endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeWheel( tree, "endsAt", "td.components-hour", 1, -1 * 3600 * 1000 ); }); it("clicking on the minute inc button adds 1m to endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeButton(tree, "endsAt", 1, /angle-up/, 60 * 1000); }); it("scrolling up on the minute button adds 1m to endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeWheel( tree, "endsAt", "td.components-minute-up", -10, 60 * 1000 ); }); it("clicking on the hour dec button subtracts 1h from endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeButton(tree, "endsAt", 2, /angle-down/, -1 * 3600 * 1000); }); it("scrolling down on the hour button subtracts 1h from endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeWheel( tree, "endsAt", "td.components-hour-down", 1, -1 * 3600 * 1000 ); }); it("clicking on the minute dec button subtracts 1m from endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeButton(tree, "endsAt", 3, /angle-down/, -1 * 60 * 1000); }); it("scrolling down on the minute button subtracts 1m from endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeWheel( tree, "endsAt", "td.components-minute-down", 50, -1 * 60 * 1000 ); }); it("scrolling up on the minute adds 1m to endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeWheel(tree, "endsAt", "td.components-minute", -10, 60 * 1000); }); it("scrolling down on the minute subtracts 1m from endsAt", () => { const tree = MountedTabContentEnd(); ValidateTimeWheel( tree, "endsAt", "td.components-minute", 15, -1 * 60 * 1000 ); }); }); const ValidateDurationButton = (elemIndex, iconMatch, expectedDiff) => { const tree = mount( ); const button = tree.find("td > span").at(elemIndex); expect(button.html()).toMatch(iconMatch); const oldEndsAt = moment(silenceFormStore.data.endsAt); button.simulate("click"); expect(silenceFormStore.data.endsAt.toISOString()).not.toBe( oldEndsAt.toISOString() ); const diffMS = silenceFormStore.data.endsAt.diff(oldEndsAt); expect(diffMS).toBe(expectedDiff); }; const ValidateDurationWheel = (elemIndex, deltaY, expectedDiff) => { const tree = mount( ); const elem = tree.find(".components-duration").at(elemIndex); const oldEndsAt = moment(silenceFormStore.data.endsAt); elem.simulate("wheel", { deltaY: deltaY }); // fire real event so cancel listener will trigger const event = new Event("wheel", { deltaY: deltaY }); elem.getDOMNode().dispatchEvent(event); expect(silenceFormStore.data.endsAt.toISOString()).not.toBe( oldEndsAt.toISOString() ); const diffMS = silenceFormStore.data.endsAt.diff(oldEndsAt); expect(diffMS).toBe(expectedDiff); }; describe("", () => { it("clicking on the day inc button adds 1d to endsAt", () => { ValidateDurationButton(0, /angle-up/, 24 * 3600 * 1000); }); it("scrolling up on the day button adds 1d to endsAt", () => { ValidateDurationWheel(0, -1, 24 * 3600 * 1000); }); it("clicking on the day dec button subtracts 1d from endsAt", () => { ValidateDurationButton(2, /angle-down/, -1 * 24 * 3600 * 1000); }); it("scrolling down on the day button subtracts 1d from endsAt", () => { ValidateDurationWheel(0, 1, -1 * 24 * 3600 * 1000); }); it("clicking on the hour inc button adds 1h to endsAt", () => { ValidateDurationButton(3, /angle-up/, 3600 * 1000); }); it("scrolling up on the hour inc button adds 1h to endsAt", () => { ValidateDurationWheel(1, -2, 3600 * 1000); }); it("clicking on the hour dec button subtracts 1h from endsAt", () => { ValidateDurationButton(5, /angle-down/, -1 * 3600 * 1000); }); it("scrolling down on the hour dec button subtracts 1h from endsAt", () => { ValidateDurationWheel(1, 2, -1 * 3600 * 1000); }); it("clicking on the minute inc button adds 5m to endsAt", () => { ValidateDurationButton(6, /angle-up/, 5 * 60 * 1000); }); it("scrolling up on the minute inc button adds 5m to endsAt", () => { ValidateDurationWheel(2, -1, 5 * 60 * 1000); }); it("clicking on the minute dec button subtracts 5m from endsAt", () => { ValidateDurationButton(8, /angle-down/, -1 * 5 * 60 * 1000); }); it("scrolling down on the minute dec button subtracts 5m from endsAt", () => { ValidateDurationWheel(2, 1, -1 * 5 * 60 * 1000); }); }); const SetDurationTo = (hours, minutes) => { const startsAt = moment([2060, 1, 1, 0, 0, 0]); const endsAt = moment(startsAt).add(hours, "hours").add(minutes, "minutes"); silenceFormStore.data.startsAt = startsAt; silenceFormStore.data.endsAt = endsAt; }; describe(" inc minute CalculateChangeValue", () => { it("inc on 0:1:0 duration sets 0:1:5", () => { SetDurationTo(1, 0); ValidateDurationButton(6, /angle-up/, 5 * 60 * 1000); }); it("inc on 0:1:1 duration sets 0:1:2", () => { SetDurationTo(1, 1); ValidateDurationButton(6, /angle-up/, 60 * 1000); }); it("inc on 0:1:4 duration sets 0:1:5", () => { SetDurationTo(1, 4); ValidateDurationButton(6, /angle-up/, 60 * 1000); }); it("inc on 0:1:5 duration sets 0:1:10", () => { SetDurationTo(1, 5); ValidateDurationButton(6, /angle-up/, 5 * 60 * 1000); }); it("inc on 0:1:6 duration sets 0:1:10", () => { SetDurationTo(1, 6); ValidateDurationButton(6, /angle-up/, 4 * 60 * 1000); }); it("inc on 0:0:55 duration sets 0:1:0", () => { SetDurationTo(0, 55); ValidateDurationButton(6, /angle-up/, 5 * 60 * 1000); }); }); describe(" dec minute CalculateChangeValue", () => { it("inc on 0:1:0 duration sets 0:0:55", () => { SetDurationTo(1, 0); ValidateDurationButton(8, /angle-down/, -5 * 60 * 1000); }); it("inc on 0:0:59 duration sets 0:0:55", () => { SetDurationTo(0, 59); ValidateDurationButton(8, /angle-down/, -4 * 60 * 1000); }); it("inc on 0:0:56 duration sets 0:0:55", () => { SetDurationTo(0, 56); ValidateDurationButton(8, /angle-down/, -1 * 60 * 1000); }); it("inc on 0:0:55 duration sets 0:0:50", () => { SetDurationTo(1, 0); ValidateDurationButton(8, /angle-down/, -5 * 60 * 1000); }); it("inc on 0:1:10 duration sets 0:1:5", () => { SetDurationTo(1, 10); ValidateDurationButton(8, /angle-down/, -5 * 60 * 1000); }); it("inc on 0:1:6 duration sets 0:1:5", () => { SetDurationTo(1, 6); ValidateDurationButton(8, /angle-down/, -1 * 60 * 1000); }); it("inc on 0:1:5 duration sets 0:1:0", () => { SetDurationTo(1, 5); ValidateDurationButton(8, /angle-down/, -5 * 60 * 1000); }); it("inc on 0:1:4 duration sets 0:1:3", () => { SetDurationTo(1, 4); ValidateDurationButton(8, /angle-down/, -1 * 60 * 1000); }); it("inc on 0:1:1 duration sets 0:1:0", () => { SetDurationTo(1, 1); ValidateDurationButton(8, /angle-down/, -1 * 60 * 1000); }); });