+
- this._performRequest('/short-urls', 'GET', options)
- .then((resp) => resp.data.shortUrls);
+ listShortUrls = pipe(
+ (options = {}) => reject(isNil, options),
+ (options = {}) => this._performRequest('/short-urls', 'GET', options).then((resp) => resp.data.shortUrls)
+ );
createShortUrl = (options) => {
const filteredOptions = reject((value) => isEmpty(value) || isNil(value), options);
diff --git a/src/utils/utils.js b/src/utils/utils.js
index 304116fe..917873f9 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -68,3 +68,5 @@ export const versionIsValidSemVer = (version) => {
return false;
}
};
+
+export const formatDate = (format = 'YYYY-MM-DD') => (date) => date && date.format ? date.format(format) : date;
diff --git a/src/visits/ShortUrlVisits.js b/src/visits/ShortUrlVisits.js
index bd291590..1473ca63 100644
--- a/src/visits/ShortUrlVisits.js
+++ b/src/visits/ShortUrlVisits.js
@@ -4,14 +4,14 @@ import { isEmpty, mapObjIndexed, values } from 'ramda';
import React from 'react';
import { Card } from 'reactstrap';
import PropTypes from 'prop-types';
-import DateInput from '../utils/DateInput';
+import DateRangeRow from '../utils/DateRangeRow';
import MutedMessage from '../utils/MuttedMessage';
+import { formatDate } from '../utils/utils';
import SortableBarGraph from './SortableBarGraph';
import { shortUrlVisitsType } from './reducers/shortUrlVisits';
import VisitsHeader from './VisitsHeader';
import GraphCard from './GraphCard';
import { shortUrlDetailType } from './reducers/shortUrlDetail';
-import './ShortUrlVisits.scss';
const ShortUrlVisits = (
{ processStatsFromVisits },
@@ -32,10 +32,7 @@ const ShortUrlVisits = (
loadVisits = () => {
const { match: { params }, getShortUrlVisits } = this.props;
const { shortCode } = params;
- const dates = mapObjIndexed(
- (value) => value && value.format ? value.format('YYYY-MM-DD') : value,
- this.state
- );
+ const dates = mapObjIndexed(formatDate(), this.state);
const { startDate, endDate } = dates;
// While the "page" is loaded, use the timestamp + filtering dates as memoization IDs for stats calcs
@@ -131,33 +128,19 @@ const ShortUrlVisits = (
);
};
+ const setDate = (dateField) => (date) => this.setState({ [dateField]: date }, this.loadVisits);
return (
-
-
- this.setState({ startDate: date }, this.loadVisits)}
- />
-
-
- this.setState({ endDate: date }, this.loadVisits)}
- />
-
-
+
diff --git a/test/short-urls/SearchBar.test.js b/test/short-urls/SearchBar.test.js
index 54bb8781..411e5665 100644
--- a/test/short-urls/SearchBar.test.js
+++ b/test/short-urls/SearchBar.test.js
@@ -1,8 +1,10 @@
import React from 'react';
import { shallow } from 'enzyme';
+import each from 'jest-each';
import searchBarCreator from '../../src/short-urls/SearchBar';
import SearchField from '../../src/utils/SearchField';
import Tag from '../../src/tags/helpers/Tag';
+import DateRangeRow from '../../src/utils/DateRangeRow';
describe('', () => {
let wrapper;
@@ -20,6 +22,12 @@ describe('', () => {
expect(wrapper.find(SearchField)).toHaveLength(1);
});
+ it('renders a DateRangeRow', () => {
+ wrapper = shallow();
+
+ expect(wrapper.find(DateRangeRow)).toHaveLength(1);
+ });
+
it('renders no tags when the list of tags is empty', () => {
wrapper = shallow();
@@ -53,4 +61,13 @@ describe('', () => {
tag.simulate('close');
expect(listShortUrlsMock).toHaveBeenCalledTimes(1);
});
+
+ each([ 'startDateChange', 'endDateChange' ]).it('updates short URLs list when date range changes', (event) => {
+ wrapper = shallow();
+ const dateRange = wrapper.find(DateRangeRow);
+
+ expect(listShortUrlsMock).not.toHaveBeenCalled();
+ dateRange.simulate(event);
+ expect(listShortUrlsMock).toHaveBeenCalledTimes(1);
+ });
});
diff --git a/test/short-urls/helpers/ShortUrlVisitsCount.test.js b/test/short-urls/helpers/ShortUrlVisitsCount.test.js
index 2700b38c..9949fa4c 100644
--- a/test/short-urls/helpers/ShortUrlVisitsCount.test.js
+++ b/test/short-urls/helpers/ShortUrlVisitsCount.test.js
@@ -17,7 +17,7 @@ describe('', () => {
it('just returns visits when no maxVisits is provided', () => {
const visitsCount = 45;
const wrapper = createWrapper({ visitsCount });
- const maxVisitsHelper = wrapper.find('.short-urls-row__max-visits-control');
+ const maxVisitsHelper = wrapper.find('.short-urls-visits-count__max-visits-control');
const maxVisitsTooltip = wrapper.find(UncontrolledTooltip);
expect(wrapper.html()).toEqual(`${visitsCount}`);
@@ -30,7 +30,7 @@ describe('', () => {
const maxVisits = 500;
const meta = { maxVisits };
const wrapper = createWrapper({ visitsCount, meta });
- const maxVisitsHelper = wrapper.find('.short-urls-row__max-visits-control');
+ const maxVisitsHelper = wrapper.find('.short-urls-visits-count__max-visits-control');
const maxVisitsTooltip = wrapper.find(UncontrolledTooltip);
expect(wrapper.html()).toContain(`/ ${maxVisits}`);
diff --git a/test/utils/DateRangeRow.test.js b/test/utils/DateRangeRow.test.js
new file mode 100644
index 00000000..5b6a4cc5
--- /dev/null
+++ b/test/utils/DateRangeRow.test.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import DateRangeRow from '../../src/utils/DateRangeRow';
+import DateInput from '../../src/utils/DateInput';
+
+describe('', () => {
+ let wrapper;
+ const onEndDateChange = jest.fn();
+ const onStartDateChange = jest.fn();
+
+ beforeEach(() => {
+ wrapper = shallow();
+ });
+ afterEach(() => {
+ wrapper.unmount();
+ jest.clearAllMocks();
+ });
+
+ it('renders two date inputs', () => {
+ const dateInput = wrapper.find(DateInput);
+
+ expect(dateInput).toHaveLength(2);
+ });
+
+ it('invokes start date callback when change event is triggered on first input', () => {
+ const dateInput = wrapper.find(DateInput).first();
+
+ expect(onStartDateChange).not.toHaveBeenCalled();
+ dateInput.simulate('change');
+ expect(onStartDateChange).toHaveBeenCalled();
+ });
+
+ it('invokes end date callback when change event is triggered on second input', () => {
+ const dateInput = wrapper.find(DateInput).last();
+
+ expect(onEndDateChange).not.toHaveBeenCalled();
+ dateInput.simulate('change');
+ expect(onEndDateChange).toHaveBeenCalled();
+ });
+});
diff --git a/test/visits/ShortUrlVisits.test.js b/test/visits/ShortUrlVisits.test.js
index e7006c75..40d634c5 100644
--- a/test/visits/ShortUrlVisits.test.js
+++ b/test/visits/ShortUrlVisits.test.js
@@ -5,8 +5,8 @@ import { Card } from 'reactstrap';
import createShortUrlVisits from '../../src/visits/ShortUrlVisits';
import MutedMessage from '../../src/utils/MuttedMessage';
import GraphCard from '../../src/visits/GraphCard';
-import DateInput from '../../src/utils/DateInput';
import SortableBarGraph from '../../src/visits/SortableBarGraph';
+import DateRangeRow from '../../src/utils/DateRangeRow';
describe('', () => {
let wrapper;
@@ -82,14 +82,15 @@ describe('', () => {
it('reloads visits when selected dates change', () => {
const wrapper = createComponent({ loading: false, error: false, visits: [{}, {}, {}] });
- const dateInput = wrapper.find(DateInput).first();
+ const dateRange = wrapper.find(DateRangeRow);
- dateInput.simulate('change', '2016-01-01T00:00:00+01:00');
- dateInput.simulate('change', '2016-01-02T00:00:00+01:00');
- dateInput.simulate('change', '2016-01-03T00:00:00+01:00');
+ dateRange.simulate('startDateChange', '2016-01-01T00:00:00+01:00');
+ dateRange.simulate('endDateChange', '2016-01-02T00:00:00+01:00');
+ dateRange.simulate('endDateChange', '2016-01-03T00:00:00+01:00');
expect(getShortUrlVisitsMock).toHaveBeenCalledTimes(4);
- expect(wrapper.state('startDate')).toEqual('2016-01-03T00:00:00+01:00');
+ expect(wrapper.state('startDate')).toEqual('2016-01-01T00:00:00+01:00');
+ expect(wrapper.state('endDate')).toEqual('2016-01-03T00:00:00+01:00');
});
it('holds the map button content generator on cities graph extraHeaderContent', () => {