dateRange.spec.jsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. import MockDate from 'mockdate';
  2. import {mountWithTheme} from 'sentry-test/enzyme';
  3. import DateRange from 'sentry/components/organizations/timeRangeSelector/dateRange';
  4. import ConfigStore from 'sentry/stores/configStore';
  5. // 2017-10-14T02:38:00.000Z
  6. // 2017-10-17T02:38:00.000Z
  7. const start = new Date(1507948680000);
  8. const end = new Date(1508207880000); // National Pasta Day
  9. const getSelectedRange = wrapper => [
  10. wrapper.find('.rdrStartEdge').closest('DayCell').find('.rdrDayNumber span').text(),
  11. ...wrapper
  12. .find('.rdrInRange')
  13. .map(el => el.closest('DayCell').find('.rdrDayNumber span').text()),
  14. wrapper.find('.rdrEndEdge').closest('DayCell').find('.rdrDayNumber span').text(),
  15. ];
  16. function getTimeText(element) {
  17. const valueRegex = /value="([0-9]{2}:[0-9]{2})"/;
  18. return element.html().match(valueRegex)[1];
  19. }
  20. describe('DateRange', function () {
  21. let wrapper;
  22. const onChange = jest.fn();
  23. const routerContext = TestStubs.routerContext();
  24. beforeAll(function () {
  25. MockDate.set(new Date('2017-10-16T23:41:20.000Z'));
  26. ConfigStore.loadInitialData({
  27. user: {options: {timezone: 'America/New_York'}},
  28. });
  29. });
  30. afterAll(function () {
  31. // reset mock date
  32. MockDate.set(new Date(1508208080000));
  33. });
  34. describe('Local time', function () {
  35. beforeEach(function () {
  36. onChange.mockReset();
  37. });
  38. beforeEach(async function () {
  39. wrapper = mountWithTheme(
  40. <DateRange
  41. start={start}
  42. end={end}
  43. showTimePicker
  44. onChange={onChange}
  45. onChangeUtc={jest.fn()}
  46. organization={TestStubs.Organization()}
  47. />,
  48. routerContext
  49. );
  50. await tick();
  51. await tick();
  52. wrapper.update();
  53. });
  54. it('has the right max date', function () {
  55. expect(wrapper.find('DateRangePicker').at(0).prop('maxDate')).toEqual(
  56. new Date('2017-10-16T23:41:20.000Z')
  57. );
  58. });
  59. it('has the right days selected', function () {
  60. // start/end inputs
  61. const startEndInputs = wrapper.find(
  62. '.rdrDateRangeWrapper .rdrDateDisplayItem input'
  63. );
  64. expect(startEndInputs.at(0).prop('value')).toBe('Oct 13, 2017');
  65. expect(startEndInputs.at(1).prop('value')).toBe('Oct 16, 2017');
  66. expect(getSelectedRange(wrapper)).toEqual(['13', '14', '15', '16']);
  67. });
  68. it('can select a date (midnight)', function () {
  69. wrapper.find('DayCell').at(0).simulate('mouseUp');
  70. //
  71. expect(onChange).toHaveBeenLastCalledWith({
  72. start: new Date('2017-10-01T04:00:00.000Z'),
  73. end: new Date('2017-10-02T03:59:59.000Z'),
  74. });
  75. });
  76. it('changes start time for existing date', function () {
  77. wrapper
  78. .find('input[data-test-id="startTime"]')
  79. .simulate('change', {target: {value: '11:00'}});
  80. expect(onChange).toHaveBeenLastCalledWith({
  81. start: new Date('2017-10-13T15:00:00.000Z'),
  82. end: new Date('2017-10-17T02:38:00.000Z'),
  83. hasDateRangeErrors: false,
  84. });
  85. });
  86. it('changes end time for existing date', function () {
  87. wrapper
  88. .find('input[data-test-id="endTime"]')
  89. .simulate('change', {target: {value: '12:00'}});
  90. expect(onChange).toHaveBeenLastCalledWith({
  91. start: new Date('2017-10-14T02:38:00.000Z'),
  92. end: new Date('2017-10-16T16:00:00.000Z'),
  93. hasDateRangeErrors: false,
  94. });
  95. });
  96. it('does not change for bad start/end time', function () {
  97. wrapper
  98. .find('input[data-test-id="startTime"]')
  99. .simulate('change', {target: {value: null}});
  100. expect(onChange).not.toHaveBeenLastCalledWith();
  101. wrapper
  102. .find('input[data-test-id="endTime"]')
  103. .simulate('change', {target: {value: null}});
  104. expect(onChange).not.toHaveBeenLastCalledWith();
  105. });
  106. it('updates start time input only if not focused', async function () {
  107. const time = start.getTime() + 60000;
  108. expect(getTimeText(wrapper.find('input[data-test-id="startTime"]'))).toEqual(
  109. '22:38'
  110. );
  111. wrapper.find('input[data-test-id="startTime"]').simulate('focus');
  112. await tick();
  113. wrapper.update();
  114. wrapper.setProps({start: new Date(time)});
  115. await tick();
  116. wrapper.update();
  117. // because the prop change happened while the component still has focus, no update
  118. expect(getTimeText(wrapper.find('input[data-test-id="startTime"]'))).toEqual(
  119. '22:38'
  120. );
  121. wrapper.find('input[data-test-id="startTime"]').simulate('blur');
  122. await tick();
  123. wrapper.update();
  124. wrapper.setProps({start: new Date(time)});
  125. await tick();
  126. wrapper.update();
  127. // because the prop change happened after the component lost focus, it updates
  128. expect(getTimeText(wrapper.find('input[data-test-id="startTime"]'))).toEqual(
  129. '22:39'
  130. );
  131. });
  132. it('updates end time input only if not focused', async function () {
  133. const time = end.getTime() + 60000;
  134. expect(getTimeText(wrapper.find('input[data-test-id="endTime"]'))).toEqual('22:38');
  135. wrapper.find('input[data-test-id="endTime"]').simulate('focus');
  136. await tick();
  137. wrapper.update();
  138. wrapper.setProps({end: new Date(time)});
  139. await tick();
  140. wrapper.update();
  141. // because the prop change happened while the component still has focus, no update
  142. expect(getTimeText(wrapper.find('input[data-test-id="endTime"]'))).toEqual('22:38');
  143. wrapper.find('input[data-test-id="endTime"]').simulate('blur');
  144. await tick();
  145. wrapper.update();
  146. wrapper.setProps({end: new Date(time)});
  147. await tick();
  148. wrapper.update();
  149. // because the prop change happened after the component lost focus, it updates
  150. expect(getTimeText(wrapper.find('input[data-test-id="endTime"]'))).toEqual('22:39');
  151. });
  152. });
  153. describe('UTC', function () {
  154. beforeEach(function () {
  155. onChange.mockReset();
  156. wrapper = mountWithTheme(
  157. <DateRange
  158. start={start}
  159. end={end}
  160. showTimePicker
  161. utc
  162. onChange={onChange}
  163. onChangeUtc={jest.fn()}
  164. organization={TestStubs.Organization()}
  165. />,
  166. routerContext
  167. );
  168. });
  169. it('has the right max date', function () {
  170. expect(wrapper.find('DateRangePicker').at(0).prop('maxDate')).toEqual(
  171. new Date('2017-10-16T23:41:20.000Z')
  172. );
  173. });
  174. it('has the right days selected', function () {
  175. // start/end inputs
  176. const startEndInputs = wrapper.find(
  177. '.rdrDateRangeWrapper .rdrDateDisplayItem input'
  178. );
  179. expect(startEndInputs.at(0).prop('value')).toBe('Oct 13, 2017');
  180. expect(startEndInputs.at(1).prop('value')).toBe('Oct 16, 2017');
  181. expect(getSelectedRange(wrapper)).toEqual(['13', '14', '15', '16']);
  182. });
  183. it('can select a date (midnight)', function () {
  184. wrapper.find('DayCell').at(0).simulate('mouseUp');
  185. //
  186. expect(onChange).toHaveBeenLastCalledWith({
  187. start: new Date('2017-10-01T04:00:00.000Z'),
  188. end: new Date('2017-10-02T03:59:59.000Z'),
  189. });
  190. });
  191. it('changes utc start time for existing date', function () {
  192. wrapper
  193. .find('input[data-test-id="startTime"]')
  194. .simulate('change', {target: {value: '11:00'}});
  195. // Initial start date is 2017-10-13T22:38:00-0400
  196. expect(onChange).toHaveBeenLastCalledWith({
  197. start: new Date('2017-10-13T15:00:00.000Z'),
  198. end: new Date('2017-10-17T02:38:00.000Z'),
  199. hasDateRangeErrors: false,
  200. });
  201. });
  202. it('changes utc end time for existing date', function () {
  203. wrapper
  204. .find('input[data-test-id="endTime"]')
  205. .simulate('change', {target: {value: '12:00'}});
  206. // Initial end time is 2017-10-16T22:38:00-0400
  207. // Setting this to 12:00 means 2017-10-16T12:00-0400
  208. expect(onChange).toHaveBeenLastCalledWith({
  209. start: new Date('2017-10-14T02:38:00.000Z'),
  210. end: new Date('2017-10-16T16:00:00.000Z'),
  211. hasDateRangeErrors: false,
  212. });
  213. });
  214. it('does not change for bad start/end time', function () {
  215. wrapper
  216. .find('input[data-test-id="startTime"]')
  217. .simulate('change', {target: {value: null}});
  218. expect(onChange).not.toHaveBeenLastCalledWith();
  219. wrapper
  220. .find('input[data-test-id="endTime"]')
  221. .simulate('change', {target: {value: null}});
  222. expect(onChange).not.toHaveBeenLastCalledWith();
  223. });
  224. it('updates utc start time input only if not focused', async function () {
  225. // NOTE: the DateRange component initializes the time inputs with the local time
  226. const time = start.getTime() + 60000;
  227. expect(getTimeText(wrapper.find('input[data-test-id="startTime"]'))).toEqual(
  228. '22:38'
  229. );
  230. wrapper.find('input[data-test-id="startTime"]').simulate('focus');
  231. await tick();
  232. wrapper.update();
  233. wrapper.setProps({start: new Date(time)});
  234. await tick();
  235. wrapper.update();
  236. // because the prop change happened while the component still has focus, no update
  237. expect(getTimeText(wrapper.find('input[data-test-id="startTime"]'))).toEqual(
  238. '22:38'
  239. );
  240. wrapper.find('input[data-test-id="startTime"]').simulate('blur');
  241. await tick();
  242. wrapper.update();
  243. wrapper.setProps({start: new Date(time)});
  244. await tick();
  245. wrapper.update();
  246. // because the prop change happened after the component lost focus, it updates
  247. expect(getTimeText(wrapper.find('input[data-test-id="startTime"]'))).toEqual(
  248. '22:39'
  249. );
  250. });
  251. it('updates utc end time input only if not focused', async function () {
  252. // NOTE: the DateRange component initializes the time inputs with the local time
  253. const time = end.getTime() + 60000;
  254. expect(getTimeText(wrapper.find('input[data-test-id="endTime"]'))).toEqual('22:38');
  255. wrapper.find('input[data-test-id="endTime"]').simulate('focus');
  256. await tick();
  257. wrapper.update();
  258. wrapper.setProps({end: new Date(time)});
  259. await tick();
  260. wrapper.update();
  261. // because the prop change happened while the component still has focus, no update
  262. expect(getTimeText(wrapper.find('input[data-test-id="endTime"]'))).toEqual('22:38');
  263. wrapper.find('input[data-test-id="endTime"]').simulate('blur');
  264. await tick();
  265. wrapper.update();
  266. wrapper.setProps({end: new Date(time)});
  267. await tick();
  268. wrapper.update();
  269. // because the prop change happened after the component lost focus, it updates
  270. expect(getTimeText(wrapper.find('input[data-test-id="endTime"]'))).toEqual('22:39');
  271. });
  272. });
  273. });