organizationContext.spec.jsx 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. import React from 'react';
  2. import {mount} from 'sentry-test/enzyme';
  3. import {openSudo} from 'app/actionCreators/modal';
  4. import * as OrganizationActionCreator from 'app/actionCreators/organization';
  5. import ConfigStore from 'app/stores/configStore';
  6. import {OrganizationContext} from 'app/views/organizationContext';
  7. import ProjectsStore from 'app/stores/projectsStore';
  8. import TeamStore from 'app/stores/teamStore';
  9. import GlobalSelectionStore from 'app/stores/globalSelectionStore';
  10. import OrganizationStore from 'app/stores/organizationStore';
  11. jest.mock('app/stores/configStore', () => ({
  12. get: jest.fn(),
  13. }));
  14. jest.mock('app/actionCreators/modal', () => ({
  15. openSudo: jest.fn(),
  16. }));
  17. describe('OrganizationContext', function() {
  18. let wrapper;
  19. const org = TestStubs.Organization({
  20. teams: [TestStubs.Team()],
  21. projects: [TestStubs.Project()],
  22. });
  23. const api = new MockApiClient();
  24. let getOrgMock;
  25. const createWrapper = props => {
  26. wrapper = mount(
  27. <OrganizationContext
  28. api={api}
  29. params={{orgId: 'org-slug'}}
  30. location={{query: {}}}
  31. routes={[]}
  32. {...props}
  33. >
  34. <div />
  35. </OrganizationContext>
  36. );
  37. return wrapper;
  38. };
  39. beforeEach(function() {
  40. MockApiClient.clearMockResponses();
  41. getOrgMock = MockApiClient.addMockResponse({
  42. url: '/organizations/org-slug/',
  43. body: org,
  44. });
  45. jest.spyOn(TeamStore, 'loadInitialData');
  46. jest.spyOn(ProjectsStore, 'loadInitialData');
  47. jest.spyOn(GlobalSelectionStore, 'loadInitialData');
  48. jest.spyOn(OrganizationActionCreator, 'fetchOrganizationDetails');
  49. });
  50. afterEach(async function() {
  51. wrapper.unmount();
  52. OrganizationStore.reset();
  53. // await for store change to finish propagating
  54. await tick();
  55. TeamStore.loadInitialData.mockRestore();
  56. ProjectsStore.loadInitialData.mockRestore();
  57. ConfigStore.get.mockRestore();
  58. GlobalSelectionStore.loadInitialData.mockRestore();
  59. OrganizationActionCreator.fetchOrganizationDetails.mockRestore();
  60. });
  61. it('renders and fetches org', async function() {
  62. wrapper = createWrapper();
  63. // await dispatching the action to org store
  64. await tick();
  65. // await resolving the api promise from action creator and updating component
  66. await tick();
  67. expect(getOrgMock).toHaveBeenCalledWith(
  68. '/organizations/org-slug/',
  69. expect.anything()
  70. );
  71. expect(wrapper.state('loading')).toBe(false);
  72. expect(wrapper.state('error')).toBe(null);
  73. expect(wrapper.state('organization')).toEqual(org);
  74. expect(TeamStore.loadInitialData).toHaveBeenCalledWith(org.teams);
  75. expect(ProjectsStore.loadInitialData).toHaveBeenCalledWith(org.projects);
  76. expect(OrganizationActionCreator.fetchOrganizationDetails).toHaveBeenCalledWith(
  77. api,
  78. 'org-slug',
  79. true
  80. );
  81. expect(GlobalSelectionStore.loadInitialData).toHaveBeenCalledWith(org, {});
  82. });
  83. it('fetches new org when router params change', async function() {
  84. wrapper = createWrapper();
  85. await tick();
  86. await tick();
  87. const mock = MockApiClient.addMockResponse({
  88. url: '/organizations/new-slug/',
  89. body: org,
  90. });
  91. wrapper.setProps({params: {orgId: 'new-slug'}});
  92. // await fetching new org
  93. await tick();
  94. wrapper.update();
  95. expect(mock).toHaveBeenLastCalledWith('/organizations/new-slug/', expect.anything());
  96. });
  97. it('shows loading error for non-superusers on 403s', async function() {
  98. getOrgMock = MockApiClient.addMockResponse({
  99. url: '/organizations/org-slug/',
  100. statusCode: 403,
  101. });
  102. console.error = jest.fn(); // eslint-disable-line no-console
  103. wrapper = createWrapper();
  104. // await dispatching action
  105. await tick();
  106. // await resolving api, and updating component
  107. await tick();
  108. wrapper.update();
  109. expect(wrapper.find('LoadingError')).toHaveLength(1);
  110. console.error.mockRestore(); // eslint-disable-line no-console
  111. });
  112. it('opens sudo modal for superusers on 403s', async function() {
  113. ConfigStore.get.mockImplementation(() => ({
  114. isSuperuser: true,
  115. }));
  116. getOrgMock = MockApiClient.addMockResponse({
  117. url: '/organizations/org-slug/',
  118. statusCode: 403,
  119. });
  120. wrapper = createWrapper();
  121. // await dispatching action
  122. await tick();
  123. // await resolving api, and updating component
  124. await tick();
  125. wrapper.update();
  126. expect(openSudo).toHaveBeenCalled();
  127. });
  128. it('uses last organization from ConfigStore', async function() {
  129. getOrgMock = MockApiClient.addMockResponse({
  130. url: '/organizations/lastOrganization/',
  131. body: org,
  132. });
  133. // mocking `.get('lastOrganization')`
  134. ConfigStore.get.mockImplementation(() => 'lastOrganization');
  135. wrapper = createWrapper({useLastOrganization: true, params: {}});
  136. // await dispatching action
  137. await tick();
  138. // await dispatching the action to org store
  139. await tick();
  140. expect(getOrgMock).toHaveBeenLastCalledWith(
  141. '/organizations/lastOrganization/',
  142. expect.anything()
  143. );
  144. });
  145. it('uses last organization from `organizations` prop', async function() {
  146. MockApiClient.addMockResponse({
  147. url: '/organizations/foo/environments/',
  148. body: TestStubs.Environments(),
  149. });
  150. getOrgMock = MockApiClient.addMockResponse({
  151. url: '/organizations/foo/',
  152. body: org,
  153. });
  154. ConfigStore.get.mockImplementation(() => '');
  155. wrapper = createWrapper({
  156. useLastOrganization: true,
  157. params: {orgId: 'foo'},
  158. organizationsLoading: true,
  159. organizations: [],
  160. });
  161. expect(wrapper.find('LoadingIndicator')).toHaveLength(1);
  162. wrapper.setProps({
  163. organizationsLoading: false,
  164. organizations: [
  165. TestStubs.Organization({slug: 'foo'}),
  166. TestStubs.Organization({slug: 'bar'}),
  167. ],
  168. });
  169. wrapper.update();
  170. await tick();
  171. wrapper.update();
  172. expect(wrapper.find('LoadingIndicator')).toHaveLength(0);
  173. expect(getOrgMock).toHaveBeenLastCalledWith('/organizations/foo/', expect.anything());
  174. });
  175. it('fetches org details only once if organizations loading store changes', async function() {
  176. wrapper = createWrapper({
  177. params: {orgId: 'org-slug'},
  178. organizationsLoading: true,
  179. organizations: [],
  180. });
  181. // await dispatching action
  182. await tick();
  183. // await resolving api, and updating component
  184. await tick();
  185. wrapper.update();
  186. expect(wrapper.find('LoadingIndicator')).toHaveLength(0);
  187. expect(getOrgMock).toHaveBeenCalledTimes(1);
  188. // Simulate OrganizationsStore being loaded *after* `OrganizationContext` finishes
  189. // org details fetch
  190. wrapper.setProps({
  191. organizationsLoading: false,
  192. organizations: [
  193. TestStubs.Organization({slug: 'foo'}),
  194. TestStubs.Organization({slug: 'bar'}),
  195. ],
  196. });
  197. expect(getOrgMock).toHaveBeenCalledTimes(1);
  198. });
  199. it('does not call `GlobalSelectionStore.loadInitialData` on group details route', async function() {
  200. expect(GlobalSelectionStore.loadInitialData).not.toHaveBeenCalled();
  201. wrapper = createWrapper({
  202. routes: [{path: '/organizations/:orgId/issues/:groupId/'}],
  203. });
  204. // await dispatching action
  205. await tick();
  206. // await resolving api, and updating component
  207. await tick();
  208. wrapper.update();
  209. expect(wrapper.state('loading')).toBe(false);
  210. expect(wrapper.state('error')).toBe(null);
  211. expect(GlobalSelectionStore.loadInitialData).not.toHaveBeenCalled();
  212. });
  213. });