index.spec.jsx 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. import React from 'react';
  2. import {mount} from 'enzyme';
  3. import {browserHistory} from 'react-router';
  4. import GlobalSelectionStore from 'app/stores/globalSelectionStore';
  5. import DiscoverContainerWithStore, {DiscoverContainer} from 'app/views/discover';
  6. import ProjectsStore from 'app/stores/projectsStore';
  7. describe('DiscoverContainer', function() {
  8. beforeEach(function() {
  9. browserHistory.push = jest.fn();
  10. });
  11. afterEach(function() {
  12. MockApiClient.clearMockResponses();
  13. });
  14. describe('new query', function() {
  15. let wrapper;
  16. const organization = TestStubs.Organization({
  17. projects: [TestStubs.Project({id: '1', slug: 'test-project'})],
  18. features: ['discover'],
  19. });
  20. beforeEach(async function() {
  21. MockApiClient.addMockResponse({
  22. url: '/organizations/org-slug/discover/query/?per_page=1000&cursor=0:0:1',
  23. method: 'POST',
  24. body: {
  25. data: [{tags_key: 'tag1', count: 5}, {tags_key: 'tag2', count: 1}],
  26. timing: {},
  27. meta: [],
  28. },
  29. });
  30. wrapper = mount(
  31. <DiscoverContainer
  32. location={{query: {}, search: ''}}
  33. params={{}}
  34. selection={{projects: [], environments: [], datetime: {}}}
  35. organization={organization}
  36. />,
  37. TestStubs.routerContext()
  38. );
  39. await tick();
  40. });
  41. it('fetches tags', function() {
  42. const queryBuilder = wrapper.instance().queryBuilder;
  43. expect(wrapper.state().isLoading).toBe(false);
  44. expect(queryBuilder.getColumns().some(column => column.name === 'tag1')).toBe(true);
  45. expect(queryBuilder.getColumns().some(column => column.name === 'tag2')).toBe(true);
  46. });
  47. it('sets active projects from global selection', async function() {
  48. ProjectsStore.loadInitialData(organization.projects);
  49. GlobalSelectionStore.reset({
  50. projects: [1],
  51. environments: [],
  52. datetime: {start: null, end: null, period: '14d'},
  53. });
  54. wrapper = mount(
  55. <DiscoverContainerWithStore
  56. location={{query: {}, search: ''}}
  57. params={{}}
  58. organization={organization}
  59. />,
  60. TestStubs.routerContext()
  61. );
  62. expect(wrapper.find('MultipleProjectSelector').text()).toBe('test-project');
  63. });
  64. });
  65. describe('saved query', function() {
  66. let wrapper, savedQueryMock, addMock, savedQueries;
  67. const organization = TestStubs.Organization({
  68. projects: [TestStubs.Project()],
  69. features: ['discover'],
  70. });
  71. const createWrapper = async (props, withStore) => {
  72. const Component = withStore ? DiscoverContainerWithStore : DiscoverContainer;
  73. const wrap = mount(
  74. <Component
  75. location={{query: {}, search: ''}}
  76. params={{savedQueryId: 1}}
  77. organization={organization}
  78. {...(withStore ? {} : {selection: {datetime: {}}})}
  79. {...props}
  80. />,
  81. TestStubs.routerContext()
  82. );
  83. await tick();
  84. wrap.update();
  85. return wrap;
  86. };
  87. beforeEach(async function() {
  88. savedQueries = [
  89. TestStubs.DiscoverSavedQuery({id: '1', name: 'one'}),
  90. TestStubs.DiscoverSavedQuery({
  91. id: '2',
  92. name: 'two',
  93. start: '2019-04-01T07:00:00.000Z',
  94. end: '2019-04-04T06:59:59.000Z',
  95. }),
  96. ];
  97. savedQueryMock = MockApiClient.addMockResponse({
  98. url: '/organizations/org-slug/discover/saved/1/',
  99. body: savedQueries[0],
  100. });
  101. MockApiClient.addMockResponse({
  102. url: '/organizations/org-slug/discover/saved/',
  103. body: savedQueries,
  104. });
  105. addMock = MockApiClient.addMockResponse({
  106. url: '/organizations/org-slug/discover/saved/',
  107. method: 'POST',
  108. });
  109. });
  110. describe('Without Global Header Store', function() {
  111. let request;
  112. beforeEach(async function() {
  113. request = MockApiClient.addMockResponse({
  114. url: '/organizations/org-slug/discover/query/?per_page=1000&cursor=0:0:1',
  115. method: 'POST',
  116. body: {timing: {}, data: [], meta: []},
  117. });
  118. wrapper = await createWrapper();
  119. });
  120. afterEach(function() {
  121. MockApiClient.clearMockResponses();
  122. });
  123. it('fetches saved query', function() {
  124. expect(savedQueryMock).toHaveBeenCalled();
  125. });
  126. it('navigates to and opens query with no date ranges saved', function() {
  127. const nextQueryMock = MockApiClient.addMockResponse({
  128. url: '/organizations/org-slug/discover/saved/1/',
  129. body: savedQueries[0],
  130. });
  131. expect(wrapper.find('SavedQueryListItem')).toHaveLength(2);
  132. wrapper.setProps({
  133. params: {savedQueryId: '1'},
  134. });
  135. expect(savedQueryMock).toHaveBeenCalledTimes(1);
  136. expect(nextQueryMock).toHaveBeenCalledTimes(1);
  137. expect(request).toHaveBeenLastCalledWith(
  138. expect.anything(),
  139. expect.objectContaining({
  140. data: {
  141. aggregations: [],
  142. conditions: [],
  143. fields: ['test'],
  144. limit: expect.any(Number),
  145. orderby: expect.any(String),
  146. projects: [2],
  147. range: '14d',
  148. },
  149. })
  150. );
  151. });
  152. it('navigates to and opens query with absolute dates saved', async function() {
  153. const nextQueryMock = MockApiClient.addMockResponse({
  154. url: '/organizations/org-slug/discover/saved/2/',
  155. body: savedQueries[1],
  156. });
  157. expect(wrapper.find('SavedQueryListItem')).toHaveLength(2);
  158. wrapper.setProps({
  159. params: {savedQueryId: '2'},
  160. });
  161. // This is needed because we are changing from savedQueryId: 1 --> 2,
  162. // so unliked the above, this will hit cWRP (see `createWrapper()`)
  163. await tick();
  164. wrapper.update();
  165. expect(savedQueryMock).toHaveBeenCalledTimes(1);
  166. expect(nextQueryMock).toHaveBeenCalledTimes(1);
  167. expect(request).toHaveBeenLastCalledWith(
  168. expect.anything(),
  169. expect.objectContaining({
  170. data: {
  171. aggregations: [],
  172. conditions: [],
  173. start: '2019-04-01T07:00:00.000Z',
  174. end: '2019-04-04T06:59:59.000Z',
  175. fields: ['test'],
  176. limit: expect.any(Number),
  177. orderby: expect.any(String),
  178. projects: [2],
  179. },
  180. })
  181. );
  182. });
  183. it('toggles edit mode', function() {
  184. wrapper.instance().toggleEditMode();
  185. expect(browserHistory.push).toHaveBeenCalledWith({
  186. pathname: '/organizations/org-slug/discover/saved/1/',
  187. query: {editing: 'true'},
  188. });
  189. });
  190. });
  191. it('changes date correctly', async function() {
  192. wrapper = await createWrapper({}, true);
  193. const request = MockApiClient.addMockResponse({
  194. url: '/organizations/org-slug/discover/query/?per_page=1000&cursor=0:0:1',
  195. method: 'POST',
  196. body: {timing: {}, data: [], meta: []},
  197. });
  198. wrapper.find('TimeRangeSelector HeaderItem').simulate('click');
  199. wrapper.find('SelectorItem[value="7d"]').simulate('click');
  200. await tick();
  201. wrapper.update();
  202. expect(request).toHaveBeenLastCalledWith(
  203. expect.anything(),
  204. expect.objectContaining({
  205. data: expect.objectContaining({
  206. range: '7d',
  207. start: null,
  208. end: null,
  209. utc: null,
  210. }),
  211. })
  212. );
  213. wrapper.find('TimeRangeSelector HeaderItem').simulate('click');
  214. wrapper.find('SelectorItem[value="24h"]').simulate('click');
  215. await tick();
  216. wrapper.update();
  217. // Go to New Query and try to save
  218. // We need this click because it updates component state :/
  219. wrapper
  220. .find('SidebarTabs .nav-tabs a')
  221. .first()
  222. .simulate('click');
  223. // We need to update savedQueryId because there's also logic in cWRP of container
  224. wrapper.setProps({
  225. params: {savedQueryId: undefined},
  226. });
  227. await tick();
  228. wrapper.update();
  229. wrapper.find('button[aria-label="Save"]').simulate('click');
  230. expect(addMock).toHaveBeenCalledWith(
  231. expect.anything(),
  232. expect.objectContaining({
  233. data: expect.objectContaining({
  234. range: '24h',
  235. }),
  236. })
  237. );
  238. });
  239. });
  240. describe('no access', function() {
  241. it('display no access message', async function() {
  242. const organization = TestStubs.Organization({projects: [TestStubs.Project()]});
  243. const wrapper = mount(
  244. <DiscoverContainer
  245. location={{query: {}, search: ''}}
  246. params={{}}
  247. selection={{datetime: {}}}
  248. organization={organization}
  249. />,
  250. TestStubs.routerContext()
  251. );
  252. expect(wrapper.text()).toBe("You don't have access to this feature");
  253. });
  254. });
  255. });