contextPickerModal.spec.jsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import React from 'react';
  2. import * as OrgActions from 'app/actionCreators/organizations';
  3. import {mountWithTheme} from 'sentry-test/enzyme';
  4. import {ContextPickerModal} from 'app/components/contextPickerModal';
  5. jest.mock('jquery');
  6. describe('ContextPickerModal', function() {
  7. let project, project2, org, org2;
  8. const onFinish = jest.fn();
  9. beforeEach(function() {
  10. MockApiClient.clearMockResponses();
  11. onFinish.mockReset();
  12. project = TestStubs.Project();
  13. org = TestStubs.Organization({projects: [project]});
  14. project2 = TestStubs.Project({slug: 'project2'});
  15. org2 = TestStubs.Organization({
  16. slug: 'org2',
  17. id: '21',
  18. });
  19. });
  20. const getComponent = props => (
  21. <ContextPickerModal
  22. Header={() => <div />}
  23. Body="div"
  24. nextPath="/test/:orgId/path/"
  25. organizations={[org, org2]}
  26. needOrg
  27. latestContext={{}}
  28. onFinish={onFinish}
  29. {...props}
  30. />
  31. );
  32. it('renders with only org selector when no org in latest context', function() {
  33. const wrapper = mountWithTheme(getComponent());
  34. expect(wrapper.find('StyledSelectControl[name="organization"]').exists()).toBe(true);
  35. expect(wrapper.find('StyledSelectControl[name="project"]').exists()).toBe(false);
  36. });
  37. it('fetches org details and sets as active org if there is only one org', function() {
  38. const spy = jest.spyOn(OrgActions, 'fetchOrganizationDetails');
  39. const api = MockApiClient.addMockResponse({
  40. url: `/organizations/${org2.slug}/`,
  41. });
  42. const wrapper = mountWithTheme(
  43. getComponent({organizations: [org2]}),
  44. TestStubs.routerContext()
  45. );
  46. wrapper.update();
  47. expect(spy).toHaveBeenCalledWith('org2', {
  48. setActive: true,
  49. loadProjects: true,
  50. });
  51. expect(api).toHaveBeenCalled();
  52. });
  53. it('calls onFinish after latestContext is set, if project id is not needed, and only 1 org', function() {
  54. const spy = jest.spyOn(OrgActions, 'fetchOrganizationDetails');
  55. const api = MockApiClient.addMockResponse({
  56. url: `/organizations/${org2.slug}/`,
  57. });
  58. const wrapper = mountWithTheme(
  59. getComponent({organizations: [org2]}),
  60. TestStubs.routerContext()
  61. );
  62. expect(spy).toHaveBeenCalledWith('org2', {
  63. setActive: true,
  64. loadProjects: true,
  65. });
  66. expect(api).toHaveBeenCalled();
  67. wrapper.setProps({latestContext: {organization: org2}});
  68. wrapper.update();
  69. expect(onFinish).toHaveBeenCalledWith('/test/org2/path/');
  70. });
  71. it('calls onFinish if there is only 1 org and 1 project', function() {
  72. const spy = jest.spyOn(OrgActions, 'fetchOrganizationDetails');
  73. const api = MockApiClient.addMockResponse({
  74. url: `/organizations/${org2.slug}/`,
  75. });
  76. const wrapper = mountWithTheme(
  77. getComponent({
  78. needOrg: true,
  79. needProject: true,
  80. nextPath: '/test/:orgId/path/:projectId/',
  81. organizations: [org2],
  82. }),
  83. TestStubs.routerContext()
  84. );
  85. expect(spy).toHaveBeenCalledWith('org2', {
  86. setActive: true,
  87. loadProjects: true,
  88. });
  89. expect(api).toHaveBeenCalled();
  90. wrapper.setProps({latestContext: {organization: {...org2, projects: [project2]}}});
  91. wrapper.update();
  92. expect(onFinish).toHaveBeenCalledWith('/test/org2/path/project2/');
  93. });
  94. it('selects an org and calls `onFinish` with URL with organization slug', function() {
  95. const wrapper = mountWithTheme(getComponent({}), TestStubs.routerContext());
  96. const mock = MockApiClient.addMockResponse({
  97. url: `/organizations/${org.slug}/`,
  98. });
  99. wrapper.find('StyledSelectControl[name="organization"] input').simulate('focus');
  100. expect(wrapper.find('Select[name="organization"] .Select-menu')).toHaveLength(1);
  101. wrapper
  102. .find('Select[name="organization"] Option')
  103. .first()
  104. .simulate('mouseDown');
  105. expect(onFinish).toHaveBeenCalledWith('/test/org-slug/path/');
  106. // Is not called because we don't need to fetch org details
  107. expect(mock).not.toHaveBeenCalled();
  108. });
  109. it('renders with project selector and org selector selected when org is in latest context', function() {
  110. const wrapper = mountWithTheme(
  111. getComponent({
  112. needOrg: true,
  113. needProject: true,
  114. latestContext: {
  115. organization: {
  116. ...org,
  117. projects: [project, project2],
  118. },
  119. },
  120. })
  121. );
  122. // Default to org in latest context
  123. expect(wrapper.find('StyledSelectControl[name="organization"]').prop('value')).toBe(
  124. org.slug
  125. );
  126. expect(wrapper.find('StyledSelectControl[name="project"]').prop('options')).toEqual([
  127. {value: project.slug, label: project.slug},
  128. {value: project2.slug, label: project2.slug},
  129. ]);
  130. });
  131. it('can select org and project', async function() {
  132. const spy = jest.spyOn(OrgActions, 'fetchOrganizationDetails');
  133. const api = MockApiClient.addMockResponse({
  134. url: `/organizations/${org2.slug}/`,
  135. });
  136. const wrapper = mountWithTheme(
  137. getComponent({
  138. needOrg: true,
  139. needProject: true,
  140. nextPath: '/test/:orgId/path/:projectId/',
  141. organizations: [
  142. {
  143. ...org,
  144. projects: [project],
  145. },
  146. {
  147. ...org2,
  148. projects: [project2],
  149. },
  150. ],
  151. }),
  152. TestStubs.routerContext()
  153. );
  154. // Should not have anything selected
  155. expect(wrapper.find('StyledSelectControl[name="organization"]').prop('value')).toBe(
  156. ''
  157. );
  158. spy.mockClear();
  159. // Select org2
  160. wrapper
  161. .find('StyledSelectControl[name="organization"]')
  162. .simulate('change', {value: org2.slug, label: org2.slug});
  163. wrapper.find('StyledSelectControl[name="organization"] input').simulate('focus');
  164. wrapper
  165. .find('Select[name="organization"] Option')
  166. .at(1)
  167. .simulate('mouseDown');
  168. expect(spy).toHaveBeenCalledWith('org2', {
  169. setActive: true,
  170. loadProjects: true,
  171. });
  172. expect(api).toHaveBeenCalled();
  173. // org2 should have 2 projects, project2 and project3
  174. wrapper.setProps({
  175. latestContext: {organization: {...org2, projects: [project2, {slug: 'project3'}]}},
  176. });
  177. wrapper.update();
  178. expect(wrapper.find('StyledSelectControl[name="project"]').prop('options')).toEqual([
  179. {value: project2.slug, label: project2.slug},
  180. {value: 'project3', label: 'project3'},
  181. ]);
  182. // Select project3
  183. wrapper.find('StyledSelectControl[name="project"] input').simulate('focus');
  184. wrapper
  185. .find('Select[name="project"] Option')
  186. .at(1)
  187. .simulate('mouseDown');
  188. expect(onFinish).toHaveBeenCalledWith('/test/org2/path/project3/');
  189. });
  190. });