diff --git a/superset-frontend/spec/javascripts/explore/components/DateFilterControl_spec.jsx b/superset-frontend/spec/javascripts/explore/components/DateFilterControl_spec.jsx
index 693c86950c..065f979539 100644
--- a/superset-frontend/spec/javascripts/explore/components/DateFilterControl_spec.jsx
+++ b/superset-frontend/spec/javascripts/explore/components/DateFilterControl_spec.jsx
@@ -18,14 +18,21 @@
*/
/* eslint-disable no-unused-expressions */
import React from 'react';
+import { OverlayTrigger, Popover, Tab, Tabs, Radio } from 'react-bootstrap';
import sinon from 'sinon';
import { styledMount as mount } from 'spec/helpers/theming';
-import Button from 'src/components/Button';
import Label from 'src/components/Label';
import DateFilterControl from 'src/explore/components/controls/DateFilterControl';
import ControlHeader from 'src/explore/components/ControlHeader';
+// Mock moment.js to use a specific date
+jest.mock('moment', () => {
+ const testDate = new Date('09/07/2020');
+
+ return () => jest.requireActual('moment')(testDate);
+});
+
const defaultProps = {
animation: false,
name: 'date',
@@ -41,40 +48,94 @@ describe('DateFilterControl', () => {
wrapper = mount();
});
+ it('renders', () => {
+ expect(wrapper.find(DateFilterControl)).toExist();
+ });
+
it('renders a ControlHeader', () => {
const controlHeader = wrapper.find(ControlHeader);
expect(controlHeader).toHaveLength(1);
});
- it('renders 3 Buttons', () => {
- const label = wrapper.find(Label).first();
- label.simulate('click');
- setTimeout(() => {
- expect(wrapper.find(Button)).toHaveLength(3);
- }, 10);
+
+ it('renders an OverlayTrigger', () => {
+ expect(wrapper.find(OverlayTrigger)).toExist();
});
- it('loads the right state', () => {
- const label = wrapper.find(Label).first();
- label.simulate('click');
- setTimeout(() => {
- expect(wrapper.state().num).toBe('90');
- }, 10);
+
+ it('renders a popover', () => {
+ const { overlay } = wrapper.find(OverlayTrigger).first().props();
+ const overlayWrapper = mount(overlay);
+
+ expect(overlayWrapper.find(Popover)).toExist();
});
- it('renders 2 dimmed sections', () => {
- const label = wrapper.find(Label).first();
+
+ it('calls open/close methods on trigger click', () => {
+ const open = jest.fn();
+ const close = jest.fn();
+ const props = {
+ ...defaultProps,
+ onOpenDateFilterControl: open,
+ onCloseDateFilterControl: close,
+ };
+ const testWrapper = mount();
+ const label = testWrapper.find(Label).first();
+
label.simulate('click');
- setTimeout(() => {
- expect(wrapper.find(Button)).toHaveLength(3);
- }, 10);
+ expect(open).toBeCalled();
+ expect(close).not.toBeCalled();
+ label.simulate('click');
+ expect(close).toBeCalled();
});
- it('opens and closes', () => {
- const label = wrapper.find(Label).first();
- label.simulate('click');
- setTimeout(() => {
- expect(wrapper.find('.popover')).toExist();
- expect(wrapper.find('.ok')).first().simulate('click');
- setTimeout(() => {
- expect(wrapper.find('.popover')).not.toExist();
- }, 10);
- }, 10);
+
+ it('renders two tabs in popover', () => {
+ const { overlay } = wrapper.find(OverlayTrigger).first().props();
+ const overlayWrapper = mount(overlay);
+ const popover = overlayWrapper.find(Popover).first();
+
+ expect(popover.find(Tabs)).toExist();
+ expect(popover.find(Tab)).toHaveLength(2);
+ });
+
+ it('renders default time options', () => {
+ const { overlay } = wrapper.find(OverlayTrigger).first().props();
+ const overlayWrapper = mount(overlay);
+ const defaultTab = overlayWrapper.find(Tab).first();
+
+ expect(defaultTab.find(Radio)).toExist();
+ expect(defaultTab.find(Radio)).toHaveLength(6);
+ });
+
+ it('renders tooltips over timeframe options', () => {
+ const { overlay } = wrapper.find(OverlayTrigger).first().props();
+ const overlayWrapper = mount(overlay);
+ const defaultTab = overlayWrapper.find(Tab).first();
+ const radioTrigger = defaultTab.find(OverlayTrigger);
+
+ expect(radioTrigger).toExist();
+ expect(radioTrigger).toHaveLength(6);
+ });
+
+ it('renders the correct time range in tooltip', () => {
+ const { overlay } = wrapper.find(OverlayTrigger).first().props();
+ const overlayWrapper = mount(overlay);
+ const defaultTab = overlayWrapper.find(Tab).first();
+ const triggers = defaultTab.find(OverlayTrigger);
+
+ const expectedLabels = {
+ 'Last day': '2020-09-06 < col < 2020-09-07',
+ 'Last week': '2020-08-31 < col < 2020-09-07',
+ 'Last month': '2020-08-07 < col < 2020-09-07',
+ 'Last quarter': '2020-06-07 < col < 2020-09-07',
+ 'Last year': '2019-01-01 < col < 2020-01-01',
+ 'No filter': '-∞ < col < ∞',
+ };
+
+ triggers.forEach(trigger => {
+ const { props } = trigger.props().overlay;
+ const label = props.id.split('tooltip-')[1];
+
+ expect(trigger.props().overlay.props.children).toEqual(
+ expectedLabels[label],
+ );
+ });
});
});
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl.jsx b/superset-frontend/src/explore/components/controls/DateFilterControl.jsx
index f49afda54c..bd30125153 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl.jsx
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl.jsx
@@ -128,22 +128,23 @@ function getStateFromSeparator(value) {
function getStateFromCommonTimeFrame(value) {
const units = `${value.split(' ')[1]}s`;
+ let sinceMoment;
+
+ if (value === 'No filter') {
+ sinceMoment = '';
+ } else if (units === 'years') {
+ sinceMoment = moment().utc().startOf(units).subtract(1, units);
+ } else {
+ sinceMoment = moment().utc().startOf('day').subtract(1, units);
+ }
+
return {
tab: TABS.DEFAULTS,
type: TYPES.DEFAULTS,
common: value,
- since:
- value === 'No filter'
- ? ''
- : moment()
- .utc()
- .startOf('day')
- .subtract(1, units)
- .format(MOMENT_FORMAT),
+ since: sinceMoment === '' ? '' : sinceMoment.format(MOMENT_FORMAT),
until:
- value === 'No filter'
- ? ''
- : moment().utc().startOf('day').format(MOMENT_FORMAT),
+ sinceMoment === '' ? '' : sinceMoment.add(1, units).format(MOMENT_FORMAT),
};
}
@@ -396,7 +397,6 @@ class DateFilterControl extends React.Component {
));
const timeFrames = COMMON_TIME_FRAMES.map(timeFrame => {
const nextState = getStateFromCommonTimeFrame(timeFrame);
-
const timeRange = buildTimeRangeString(nextState.since, nextState.until);
return (