index.spec.jsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. import React from 'react';
  2. import {initializeOrg} from 'app-test/helpers/initializeOrg';
  3. import {mockRouterPush} from 'app-test/helpers/mockRouterPush';
  4. import {mount} from 'enzyme';
  5. import {setActiveOrganization} from 'app/actionCreators/organizations';
  6. import GlobalSelectionStore from 'app/stores/globalSelectionStore';
  7. import EventsContainer from 'app/views/events';
  8. import ProjectsStore from 'app/stores/projectsStore';
  9. describe('EventsContainer', function() {
  10. let wrapper;
  11. const environments = ['production', 'staging'];
  12. const {organization, router, routerContext} = initializeOrg({
  13. projects: [
  14. {isMember: true, environments, isBookmarked: true},
  15. {isMember: true, slug: 'new-project', id: 3, environments},
  16. ],
  17. organization: {
  18. features: ['events', 'global-views'],
  19. },
  20. router: {
  21. location: {
  22. pathname: '/organizations/org-slug/events/',
  23. query: {},
  24. },
  25. },
  26. });
  27. beforeAll(async function() {
  28. MockApiClient.addMockResponse({
  29. url: '/organizations/org-slug/tags/',
  30. body: [{count: 1, tag: 'transaction'}, {count: 2, tag: 'mechanism'}],
  31. });
  32. setActiveOrganization(organization);
  33. await tick();
  34. });
  35. describe('Header', function() {
  36. beforeEach(function() {
  37. GlobalSelectionStore.reset();
  38. ProjectsStore.loadInitialData(organization.projects);
  39. router.location = {
  40. pathname: '/organizations/org-slug/events/',
  41. query: {},
  42. };
  43. wrapper = mount(
  44. <EventsContainer
  45. router={router}
  46. organization={organization}
  47. location={router.location}
  48. >
  49. <div />
  50. </EventsContainer>,
  51. routerContext
  52. );
  53. mockRouterPush(wrapper, router);
  54. });
  55. it('updates router when changing environments', async function() {
  56. expect(wrapper.find('PageContent')).toHaveLength(1);
  57. expect(wrapper.find('MultipleEnvironmentSelector').prop('value')).toEqual([]);
  58. wrapper.find('MultipleEnvironmentSelector HeaderItem').simulate('click');
  59. await tick();
  60. wrapper.update();
  61. wrapper
  62. .find('EnvironmentSelectorItem')
  63. .at(0)
  64. .simulate('click');
  65. await tick();
  66. wrapper.update();
  67. expect(router.push).toHaveBeenLastCalledWith({
  68. pathname: '/organizations/org-slug/events/',
  69. query: {
  70. environment: ['production'],
  71. },
  72. });
  73. await tick();
  74. wrapper.update();
  75. expect(wrapper.find('MultipleEnvironmentSelector').prop('value')).toEqual([
  76. 'production',
  77. ]);
  78. // Select a second environment, "staging"
  79. wrapper.find('MultipleEnvironmentSelector HeaderItem').simulate('click');
  80. await tick();
  81. wrapper.update();
  82. wrapper
  83. .find('EnvironmentSelectorItem')
  84. .at(1)
  85. .find('CheckboxHitbox')
  86. .simulate('click');
  87. expect(wrapper.find('MultipleEnvironmentSelector').prop('value')).toEqual([
  88. 'production',
  89. 'staging',
  90. ]);
  91. // close dropdown
  92. wrapper
  93. .find('MultipleEnvironmentSelector StyledInput')
  94. .simulate('keyDown', {key: 'Escape'});
  95. await tick();
  96. wrapper.update();
  97. expect(router.push).toHaveBeenLastCalledWith({
  98. pathname: '/organizations/org-slug/events/',
  99. query: {
  100. environment: ['production', 'staging'],
  101. },
  102. });
  103. expect(wrapper.find('MultipleEnvironmentSelector').prop('value')).toEqual([
  104. 'production',
  105. 'staging',
  106. ]);
  107. // Can clear
  108. wrapper.find('MultipleEnvironmentSelector HeaderItem').simulate('click');
  109. await tick();
  110. wrapper.update();
  111. wrapper
  112. .find('MultipleEnvironmentSelector HeaderItem StyledClose')
  113. .simulate('click');
  114. await tick();
  115. wrapper.update();
  116. expect(wrapper.find('MultipleEnvironmentSelector').prop('value')).toEqual([]);
  117. expect(router.push).toHaveBeenCalledWith({
  118. pathname: '/organizations/org-slug/events/',
  119. query: {
  120. environment: [],
  121. },
  122. });
  123. });
  124. it('updates router when changing projects', async function() {
  125. expect(wrapper.find('MultipleProjectSelector').prop('value')).toEqual([]);
  126. wrapper.find('MultipleProjectSelector HeaderItem').simulate('click');
  127. wrapper
  128. .find('MultipleProjectSelector AutoCompleteItem')
  129. .at(0)
  130. .simulate('click');
  131. await tick();
  132. wrapper.update();
  133. expect(router.push).toHaveBeenCalledWith({
  134. pathname: '/organizations/org-slug/events/',
  135. query: {
  136. project: [2],
  137. },
  138. });
  139. expect(wrapper.find('MultipleProjectSelector').prop('value')).toEqual([2]);
  140. });
  141. it('selects multiple projects', async function() {
  142. expect(wrapper.find('MultipleProjectSelector').prop('value')).toEqual([]);
  143. wrapper.find('MultipleProjectSelector HeaderItem').simulate('click');
  144. wrapper
  145. .find('MultipleProjectSelector AutoCompleteItem CheckboxHitbox')
  146. .at(0)
  147. .simulate('click');
  148. expect(wrapper.find('MultipleProjectSelector').prop('value')).toEqual([2]);
  149. wrapper
  150. .find('MultipleProjectSelector AutoCompleteItem CheckboxHitbox')
  151. .at(1)
  152. .simulate('click');
  153. expect(wrapper.find('MultipleProjectSelector').prop('value')).toEqual([2, 3]);
  154. wrapper.find('MultipleProjectSelector StyledChevron').simulate('click');
  155. expect(router.push).toHaveBeenCalledWith({
  156. pathname: '/organizations/org-slug/events/',
  157. query: {
  158. project: [2, 3],
  159. },
  160. });
  161. });
  162. it('changes to absolute time (utc is default)', async function() {
  163. const start = new Date('2017-10-01T00:00:00.000Z');
  164. const end = new Date('2017-10-01T23:59:59.000Z');
  165. wrapper.find('TimeRangeSelector HeaderItem').simulate('click');
  166. await wrapper.find('SelectorItem[value="absolute"]').simulate('click');
  167. // Oct 1st
  168. wrapper
  169. .find('DayCell')
  170. .at(0)
  171. .simulate('mouseUp');
  172. expect(wrapper.find('UtcPicker Checkbox').prop('checked')).toBe(true);
  173. wrapper.find('TimeRangeSelector StyledChevron').simulate('click');
  174. await tick();
  175. wrapper.update();
  176. expect(router.push).toHaveBeenCalledWith({
  177. pathname: '/organizations/org-slug/events/',
  178. query: {
  179. start: '2017-10-01T00:00:00',
  180. end: '2017-10-01T23:59:59',
  181. utc: true,
  182. },
  183. });
  184. expect(wrapper.find('TimeRangeSelector').prop('start')).toEqual(start);
  185. expect(wrapper.find('TimeRangeSelector').prop('end')).toEqual(end);
  186. expect(wrapper.find('TimeRangeSelector').prop('relative')).toEqual(null);
  187. // Open menu and make sure UTC is checked
  188. wrapper.find('TimeRangeSelector HeaderItem').simulate('click');
  189. await tick();
  190. wrapper.update();
  191. expect(wrapper.find('UtcPicker Checkbox').prop('checked')).toBe(true);
  192. });
  193. it('does not update router when toggling environment selector without changes', async function() {
  194. const prevCallCount = router.push.mock.calls.length;
  195. wrapper.setProps({
  196. router: {
  197. ...router,
  198. location: {
  199. ...router.location,
  200. query: {
  201. environment: ['production'],
  202. utc: 'true',
  203. },
  204. },
  205. },
  206. });
  207. // Toggle MultipleProjectSelector
  208. wrapper.find('MultipleEnvironmentSelector HeaderItem').simulate('click');
  209. wrapper
  210. .find('MultipleEnvironmentSelector StyledInput')
  211. .simulate('keyDown', {key: 'Escape'});
  212. expect(router.push).toHaveBeenCalledTimes(prevCallCount);
  213. });
  214. it('updates router when changing periods', async function() {
  215. expect(wrapper.find('TimeRangeSelector').prop('start')).toEqual(null);
  216. expect(wrapper.find('TimeRangeSelector').prop('end')).toEqual(null);
  217. expect(wrapper.find('TimeRangeSelector').prop('relative')).toEqual(null);
  218. wrapper.find('TimeRangeSelector HeaderItem').simulate('click');
  219. expect(wrapper.find('[data-test-id="date-range"]')).toHaveLength(0);
  220. wrapper.find('SelectorItem[value="absolute"]').simulate('click');
  221. wrapper.find('TimeRangeSelector HeaderItem').simulate('click');
  222. await tick();
  223. wrapper.update();
  224. // The current date in local timezone is 2017-10-16T22:41:20-04:00
  225. // we take the local date and subtract 14d
  226. // If "UTC" override is true then we strip timezone and use that date for the range
  227. expect(router.push).toHaveBeenCalledWith({
  228. pathname: '/organizations/org-slug/events/',
  229. query: {
  230. end: '2017-10-16T22:41:20',
  231. start: '2017-10-02T22:41:20',
  232. utc: true,
  233. },
  234. });
  235. expect(wrapper.find('TimeRangeSelector').props()).toEqual(
  236. expect.objectContaining({
  237. end: new Date('2017-10-16T22:41:20.000Z'),
  238. start: new Date('2017-10-02T22:41:20.000Z'),
  239. utc: true,
  240. })
  241. );
  242. // Can switch back to relative date
  243. wrapper.find('TimeRangeSelector HeaderItem').simulate('click');
  244. wrapper.find('SelectorItem[value="7d"]').simulate('click');
  245. wrapper.find('TimeRangeSelector HeaderItem').simulate('click');
  246. await tick();
  247. wrapper.update();
  248. expect(wrapper.find('TimeRangeSelector').prop('relative')).toEqual('7d');
  249. // Note this is NOT called with utc true like the above because 1) it's a relative date
  250. // and we do not need UTC value (which is default true in tests because timezone is set to UTC)
  251. // and 2) we removed forcing a default value in url params so there is no explicit utc value
  252. expect(router.push).toHaveBeenCalledWith({
  253. pathname: '/organizations/org-slug/events/',
  254. query: {
  255. statsPeriod: '7d',
  256. },
  257. });
  258. expect(wrapper.find('TimeRangeSelector').props()).toEqual(
  259. expect.objectContaining({
  260. end: null,
  261. start: null,
  262. relative: '7d',
  263. })
  264. );
  265. });
  266. it('updates TimeRangeSelector when changing routes', async function() {
  267. let newRouter = {
  268. router: {
  269. ...router,
  270. location: {
  271. pathname: '/organizations/org-slug/events2/',
  272. query: {
  273. end: '2017-10-17T02:41:20',
  274. start: '2017-10-03T02:41:20',
  275. utc: 'true',
  276. },
  277. },
  278. },
  279. };
  280. wrapper.setProps(newRouter);
  281. wrapper.setContext(newRouter);
  282. await tick();
  283. wrapper.update();
  284. expect(wrapper.find('TimeRangeSelector').text()).toEqual(
  285. 'Oct 3, 201702:41toOct 17, 201702:41'
  286. );
  287. newRouter = {
  288. router: {
  289. ...router,
  290. location: {
  291. pathname: '/organizations/org-slug/events/',
  292. query: {
  293. statsPeriod: '7d',
  294. end: null,
  295. start: null,
  296. utc: 'true',
  297. },
  298. },
  299. },
  300. };
  301. wrapper.setProps(newRouter);
  302. wrapper.setContext(newRouter);
  303. await tick();
  304. wrapper.update();
  305. expect(wrapper.find('TimeRangeSelector').text()).toEqual('Last 7 days');
  306. });
  307. });
  308. });