index.spec.tsx 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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 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. ConfigStore.set('features', new Set(['relocation:enabled']));
  49. render(<OrganizationCreate />);
  50. expect(screen.getByText('Create a New Organization')).toBeInTheDocument();
  51. expect(
  52. screen.getByText('Relocating from self-hosted?', {exact: false})
  53. ).toBeInTheDocument();
  54. expect(screen.getByText('Relocating from self-hosted?')).toHaveAttribute(
  55. 'href',
  56. '/relocation/'
  57. );
  58. await userEvent.type(screen.getByPlaceholderText('e.g. My Company'), 'Good Burger');
  59. await userEvent.click(
  60. screen.getByRole('checkbox', {
  61. name: 'I agree to the Terms of Service and the Privacy Policy',
  62. })
  63. );
  64. await userEvent.click(screen.getByText('Create Organization'));
  65. await waitFor(() => {
  66. expect(orgCreateMock).toHaveBeenCalledWith('/organizations/', {
  67. success: expect.any(Function),
  68. error: expect.any(Function),
  69. method: 'POST',
  70. data: {agreeTerms: true, defaultTeam: true, name: 'Good Burger'},
  71. host: undefined,
  72. });
  73. });
  74. expect(window.location.assign).toHaveBeenCalledTimes(1);
  75. expect(window.location.assign).toHaveBeenCalledWith(
  76. '/organizations/org-slug/projects/new/'
  77. );
  78. });
  79. it('creates a new org with customer domain feature', async function () {
  80. const orgCreateMock = MockApiClient.addMockResponse({
  81. url: '/organizations/',
  82. method: 'POST',
  83. body: OrganizationFixture({
  84. features: ['customer-domains'],
  85. }),
  86. });
  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. features: ['customer-domains'],
  118. }),
  119. });
  120. ConfigStore.set('features', new Set(['organizations:multi-region-selector']));
  121. ConfigStore.set('regions', [
  122. {url: 'https://us.example.com', name: 'us'},
  123. {
  124. url: 'https://de.example.com',
  125. name: 'de',
  126. },
  127. ]);
  128. return orgCreateMock;
  129. }
  130. it('renders without region data and submits without host when only a single region is defined', async function () {
  131. const orgCreateMock = multiRegionSetup();
  132. // Set only a single region in the config store
  133. ConfigStore.set('regions', [{name: '--monolith--', url: 'https://example.com'}]);
  134. render(<OrganizationCreate />);
  135. expect(screen.queryByLabelText('Data Storage Location')).not.toBeInTheDocument();
  136. await userEvent.type(screen.getByPlaceholderText('e.g. My Company'), 'Good Burger');
  137. await userEvent.click(screen.getByText('Create Organization'));
  138. await waitFor(() => {
  139. expect(orgCreateMock).toHaveBeenCalledWith('/organizations/', {
  140. success: expect.any(Function),
  141. error: expect.any(Function),
  142. method: 'POST',
  143. host: undefined,
  144. data: {defaultTeam: true, name: 'Good Burger'},
  145. });
  146. });
  147. expect(window.location.assign).toHaveBeenCalledTimes(1);
  148. expect(window.location.assign).toHaveBeenCalledWith(
  149. 'https://org-slug.sentry.io/projects/new/'
  150. );
  151. });
  152. it('renders without a pre-selected region, and does not submit until one is selected', async function () {
  153. const orgCreateMock = multiRegionSetup();
  154. render(<OrganizationCreate />);
  155. expect(screen.getByLabelText('Data Storage Location')).toBeInTheDocument();
  156. const link = screen.getByText<HTMLAnchorElement>('Learn More');
  157. expect(link).toBeInTheDocument();
  158. expect(link.href).toBe(DATA_STORAGE_DOCS_LINK);
  159. await userEvent.type(screen.getByPlaceholderText('e.g. My Company'), 'Good Burger');
  160. await userEvent.click(screen.getByText('Create Organization'));
  161. expect(orgCreateMock).not.toHaveBeenCalled();
  162. expect(window.location.assign).not.toHaveBeenCalled();
  163. await selectEvent.select(
  164. screen.getByRole('textbox', {name: 'Data Storage Location'}),
  165. '🇺🇸 United States of America (US)'
  166. );
  167. await userEvent.click(screen.getByText('Create Organization'));
  168. const expectedHost = 'https://us.example.com';
  169. await waitFor(() => {
  170. expect(orgCreateMock).toHaveBeenCalledWith('/organizations/', {
  171. success: expect.any(Function),
  172. error: expect.any(Function),
  173. method: 'POST',
  174. host: expectedHost,
  175. data: {defaultTeam: true, name: 'Good Burger'},
  176. });
  177. });
  178. expect(window.location.assign).toHaveBeenCalledTimes(1);
  179. expect(window.location.assign).toHaveBeenCalledWith(
  180. 'https://org-slug.sentry.io/projects/new/'
  181. );
  182. });
  183. it('renders without region data and submits without host when the feature flag is not enabled', async function () {
  184. const orgCreateMock = multiRegionSetup();
  185. ConfigStore.set('features', new Set());
  186. render(<OrganizationCreate />);
  187. expect(screen.queryByLabelText('Data Storage Location')).not.toBeInTheDocument();
  188. await userEvent.type(screen.getByPlaceholderText('e.g. My Company'), 'Good Burger');
  189. await userEvent.click(screen.getByText('Create Organization'));
  190. await waitFor(() => {
  191. expect(orgCreateMock).toHaveBeenCalledWith('/organizations/', {
  192. success: expect.any(Function),
  193. error: expect.any(Function),
  194. method: 'POST',
  195. host: undefined,
  196. data: {defaultTeam: true, name: 'Good Burger'},
  197. });
  198. });
  199. expect(window.location.assign).toHaveBeenCalledTimes(1);
  200. expect(window.location.assign).toHaveBeenCalledWith(
  201. 'https://org-slug.sentry.io/projects/new/'
  202. );
  203. });
  204. it('uses the host of the selected region when submitting', async function () {
  205. const orgCreateMock = multiRegionSetup();
  206. render(<OrganizationCreate />);
  207. expect(screen.getByLabelText('Data Storage Location')).toBeInTheDocument();
  208. const link = screen.getByText<HTMLAnchorElement>('Learn More');
  209. expect(link).toBeInTheDocument();
  210. expect(link.href).toBe(DATA_STORAGE_DOCS_LINK);
  211. await userEvent.type(screen.getByPlaceholderText('e.g. My Company'), 'Good Burger');
  212. await selectEvent.select(
  213. screen.getByRole('textbox', {name: 'Data Storage Location'}),
  214. '🇪🇺 European Union (EU)'
  215. );
  216. await userEvent.click(screen.getByText('Create Organization'));
  217. const expectedHost = 'https://de.example.com';
  218. await waitFor(() => {
  219. expect(orgCreateMock).toHaveBeenCalledWith('/organizations/', {
  220. success: expect.any(Function),
  221. error: expect.any(Function),
  222. method: 'POST',
  223. host: expectedHost,
  224. data: {defaultTeam: true, name: 'Good Burger'},
  225. });
  226. });
  227. expect(window.location.assign).toHaveBeenCalledTimes(1);
  228. expect(window.location.assign).toHaveBeenCalledWith(
  229. 'https://org-slug.sentry.io/projects/new/'
  230. );
  231. });
  232. });