index.spec.tsx 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. import selectEvent from 'react-select-event';
  2. import {OrganizationFixture} from 'sentry-fixture/organization';
  3. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  4. import ConfigStore from 'sentry/stores/configStore';
  5. import OrganizationCreate, {
  6. DATA_STORAGE_DOCS_LINK,
  7. } from 'sentry/views/organizationCreate';
  8. describe('OrganizationCreate', function () {
  9. let oldRegions: any[] = [];
  10. beforeEach(() => {
  11. ConfigStore.get('termsUrl');
  12. ConfigStore.get('privacyUrl');
  13. oldRegions = ConfigStore.get('regions');
  14. // Set only a single region in the config store by default
  15. ConfigStore.set('regions', [{name: '--monolith--', url: 'https://example.com'}]);
  16. });
  17. afterEach(() => {
  18. MockApiClient.clearMockResponses();
  19. jest.resetAllMocks();
  20. ConfigStore.set('regions', oldRegions);
  21. });
  22. it('renders without terms', function () {
  23. render(<OrganizationCreate />);
  24. });
  25. it('renders with terms', function () {
  26. ConfigStore.set('termsUrl', 'https://example.com/terms');
  27. ConfigStore.set('privacyUrl', 'https://example.com/privacy');
  28. render(<OrganizationCreate />);
  29. });
  30. it('does not render relocation url for self-hosted', function () {
  31. ConfigStore.set('termsUrl', 'https://example.com/terms');
  32. ConfigStore.set('privacyUrl', 'https://example.com/privacy');
  33. ConfigStore.set('isSelfHosted', true);
  34. render(<OrganizationCreate />);
  35. expect(() =>
  36. screen.getByText('Relocating from self-hosted?', {exact: false})
  37. ).toThrow();
  38. });
  39. it('creates a new org', async function () {
  40. const orgCreateMock = MockApiClient.addMockResponse({
  41. url: '/organizations/',
  42. method: 'POST',
  43. body: OrganizationFixture(),
  44. });
  45. ConfigStore.set('termsUrl', 'https://example.com/terms');
  46. ConfigStore.set('privacyUrl', 'https://example.com/privacy');
  47. ConfigStore.set('isSelfHosted', false);
  48. render(<OrganizationCreate />);
  49. expect(screen.getByText('Create a New Organization')).toBeInTheDocument();
  50. expect(
  51. screen.getByText('Relocating from self-hosted?', {exact: false})
  52. ).toBeInTheDocument();
  53. expect(screen.getByText('here')).toHaveAttribute('href', '/relocation/');
  54. await userEvent.type(screen.getByPlaceholderText('e.g. My Company'), 'Good Burger');
  55. await userEvent.click(
  56. screen.getByRole('checkbox', {
  57. name: 'I agree to the Terms of Service and the Privacy Policy',
  58. })
  59. );
  60. await userEvent.click(screen.getByText('Create Organization'));
  61. await waitFor(() => {
  62. expect(orgCreateMock).toHaveBeenCalledWith('/organizations/', {
  63. success: expect.any(Function),
  64. error: expect.any(Function),
  65. method: 'POST',
  66. data: {agreeTerms: true, defaultTeam: true, name: 'Good Burger'},
  67. host: undefined,
  68. });
  69. });
  70. expect(window.location.assign).toHaveBeenCalledTimes(1);
  71. expect(window.location.assign).toHaveBeenCalledWith(
  72. '/organizations/org-slug/projects/new/'
  73. );
  74. });
  75. it('creates a new org with customer domain feature', async function () {
  76. const orgCreateMock = MockApiClient.addMockResponse({
  77. url: '/organizations/',
  78. method: 'POST',
  79. body: OrganizationFixture({
  80. features: ['customer-domains'],
  81. }),
  82. });
  83. ConfigStore.set('termsUrl', 'https://example.com/terms');
  84. ConfigStore.set('privacyUrl', 'https://example.com/privacy');
  85. render(<OrganizationCreate />);
  86. expect(screen.getByText('Create a New Organization')).toBeInTheDocument();
  87. await userEvent.type(screen.getByPlaceholderText('e.g. My Company'), 'Good Burger');
  88. await userEvent.click(
  89. screen.getByRole('checkbox', {
  90. name: 'I agree to the Terms of Service and the Privacy Policy',
  91. })
  92. );
  93. await userEvent.click(screen.getByText('Create Organization'));
  94. await waitFor(() => {
  95. expect(orgCreateMock).toHaveBeenCalledWith('/organizations/', {
  96. data: {agreeTerms: true, defaultTeam: true, name: 'Good Burger'},
  97. method: 'POST',
  98. success: expect.any(Function),
  99. error: expect.any(Function),
  100. host: undefined,
  101. });
  102. });
  103. expect(window.location.assign).toHaveBeenCalledTimes(1);
  104. expect(window.location.assign).toHaveBeenCalledWith(
  105. 'https://org-slug.sentry.io/projects/new/'
  106. );
  107. });
  108. function multiRegionSetup() {
  109. const orgCreateMock = MockApiClient.addMockResponse({
  110. url: '/organizations/',
  111. method: 'POST',
  112. body: OrganizationFixture({
  113. features: ['customer-domains'],
  114. }),
  115. });
  116. ConfigStore.set('features', new Set(['organizations:multi-region-selector']));
  117. ConfigStore.set('regions', [
  118. {url: 'https://us.example.com', name: 'us'},
  119. {
  120. url: 'https://de.example.com',
  121. name: 'de',
  122. },
  123. ]);
  124. return orgCreateMock;
  125. }
  126. it('renders without region data and submits without host when only a single region is defined', async function () {
  127. const orgCreateMock = multiRegionSetup();
  128. // Set only a single region in the config store
  129. ConfigStore.set('regions', [{name: '--monolith--', url: 'https://example.com'}]);
  130. render(<OrganizationCreate />);
  131. expect(screen.queryByLabelText('Data Storage Location')).not.toBeInTheDocument();
  132. await userEvent.type(screen.getByPlaceholderText('e.g. My Company'), 'Good Burger');
  133. await userEvent.click(screen.getByText('Create Organization'));
  134. await waitFor(() => {
  135. expect(orgCreateMock).toHaveBeenCalledWith('/organizations/', {
  136. success: expect.any(Function),
  137. error: expect.any(Function),
  138. method: 'POST',
  139. host: undefined,
  140. data: {defaultTeam: true, name: 'Good Burger'},
  141. });
  142. });
  143. expect(window.location.assign).toHaveBeenCalledTimes(1);
  144. expect(window.location.assign).toHaveBeenCalledWith(
  145. 'https://org-slug.sentry.io/projects/new/'
  146. );
  147. });
  148. it('renders without a pre-selected region, and does not submit until one is selected', async function () {
  149. const orgCreateMock = multiRegionSetup();
  150. render(<OrganizationCreate />);
  151. expect(screen.getByLabelText('Data Storage Location')).toBeInTheDocument();
  152. const link = screen.getByText<HTMLAnchorElement>('Learn More');
  153. expect(link).toBeInTheDocument();
  154. expect(link.href).toBe(DATA_STORAGE_DOCS_LINK);
  155. await userEvent.type(screen.getByPlaceholderText('e.g. My Company'), 'Good Burger');
  156. await userEvent.click(screen.getByText('Create Organization'));
  157. expect(orgCreateMock).not.toHaveBeenCalled();
  158. expect(window.location.assign).not.toHaveBeenCalled();
  159. await selectEvent.select(
  160. screen.getByRole('textbox', {name: 'Data Storage Location'}),
  161. '🇺🇸 United States of America (US)'
  162. );
  163. await userEvent.click(screen.getByText('Create Organization'));
  164. const expectedHost = 'https://us.example.com';
  165. await waitFor(() => {
  166. expect(orgCreateMock).toHaveBeenCalledWith('/organizations/', {
  167. success: expect.any(Function),
  168. error: expect.any(Function),
  169. method: 'POST',
  170. host: expectedHost,
  171. data: {defaultTeam: true, name: 'Good Burger'},
  172. });
  173. });
  174. expect(window.location.assign).toHaveBeenCalledTimes(1);
  175. expect(window.location.assign).toHaveBeenCalledWith(
  176. 'https://org-slug.sentry.io/projects/new/'
  177. );
  178. });
  179. it('renders without region data and submits without host when the feature flag is not enabled', async function () {
  180. const orgCreateMock = multiRegionSetup();
  181. ConfigStore.set('features', new Set());
  182. render(<OrganizationCreate />);
  183. expect(screen.queryByLabelText('Data Storage Location')).not.toBeInTheDocument();
  184. await userEvent.type(screen.getByPlaceholderText('e.g. My Company'), 'Good Burger');
  185. await userEvent.click(screen.getByText('Create Organization'));
  186. await waitFor(() => {
  187. expect(orgCreateMock).toHaveBeenCalledWith('/organizations/', {
  188. success: expect.any(Function),
  189. error: expect.any(Function),
  190. method: 'POST',
  191. host: undefined,
  192. data: {defaultTeam: true, name: 'Good Burger'},
  193. });
  194. });
  195. expect(window.location.assign).toHaveBeenCalledTimes(1);
  196. expect(window.location.assign).toHaveBeenCalledWith(
  197. 'https://org-slug.sentry.io/projects/new/'
  198. );
  199. });
  200. it('uses the host of the selected region when submitting', async function () {
  201. const orgCreateMock = multiRegionSetup();
  202. render(<OrganizationCreate />);
  203. expect(screen.getByLabelText('Data Storage Location')).toBeInTheDocument();
  204. const link = screen.getByText<HTMLAnchorElement>('Learn More');
  205. expect(link).toBeInTheDocument();
  206. expect(link.href).toBe(DATA_STORAGE_DOCS_LINK);
  207. await userEvent.type(screen.getByPlaceholderText('e.g. My Company'), 'Good Burger');
  208. await selectEvent.select(
  209. screen.getByRole('textbox', {name: 'Data Storage Location'}),
  210. '🇪🇺 European Union (EU)'
  211. );
  212. await userEvent.click(screen.getByText('Create Organization'));
  213. const expectedHost = 'https://de.example.com';
  214. await waitFor(() => {
  215. expect(orgCreateMock).toHaveBeenCalledWith('/organizations/', {
  216. success: expect.any(Function),
  217. error: expect.any(Function),
  218. method: 'POST',
  219. host: expectedHost,
  220. data: {defaultTeam: true, name: 'Good Burger'},
  221. });
  222. });
  223. expect(window.location.assign).toHaveBeenCalledTimes(1);
  224. expect(window.location.assign).toHaveBeenCalledWith(
  225. 'https://org-slug.sentry.io/projects/new/'
  226. );
  227. });
  228. });