index.spec.tsx 8.6 KB

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