index.spec.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import {browserHistory} from 'react-router';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {
  4. act,
  5. render,
  6. renderGlobalModal,
  7. screen,
  8. userEvent,
  9. waitFor,
  10. within,
  11. } from 'sentry-test/reactTestingLibrary';
  12. import OrganizationsStore from 'sentry/stores/organizationsStore';
  13. import ProjectsStore from 'sentry/stores/projectsStore';
  14. import OrganizationGeneralSettings from 'sentry/views/settings/organizationGeneralSettings';
  15. describe('OrganizationGeneralSettings', function () {
  16. const ENDPOINT = '/organizations/org-slug/';
  17. const {organization, router} = initializeOrg();
  18. const defaultProps = {
  19. organization,
  20. router,
  21. location: router.location,
  22. params: {orgId: organization.slug},
  23. routes: router.routes,
  24. route: {},
  25. routeParams: router.params,
  26. };
  27. beforeEach(function () {
  28. OrganizationsStore.addOrReplace(organization);
  29. MockApiClient.addMockResponse({
  30. url: `/organizations/${organization.slug}/auth-provider/`,
  31. method: 'GET',
  32. });
  33. });
  34. it('can enable "early adopter"', async function () {
  35. render(<OrganizationGeneralSettings {...defaultProps} />);
  36. const mock = MockApiClient.addMockResponse({
  37. url: ENDPOINT,
  38. method: 'PUT',
  39. });
  40. userEvent.click(screen.getByRole('checkbox', {name: /early adopter/i}));
  41. await waitFor(() => {
  42. expect(mock).toHaveBeenCalledWith(
  43. ENDPOINT,
  44. expect.objectContaining({
  45. data: {isEarlyAdopter: true},
  46. })
  47. );
  48. });
  49. });
  50. it('changes org slug and redirects to new slug', async function () {
  51. render(<OrganizationGeneralSettings {...defaultProps} />);
  52. const mock = MockApiClient.addMockResponse({
  53. url: ENDPOINT,
  54. method: 'PUT',
  55. body: {...organization, slug: 'new-slug'},
  56. });
  57. userEvent.clear(screen.getByRole('textbox', {name: /slug/i}));
  58. userEvent.type(screen.getByRole('textbox', {name: /slug/i}), 'new-slug');
  59. userEvent.click(screen.getByLabelText('Save'));
  60. await waitFor(() => {
  61. expect(mock).toHaveBeenCalledWith(
  62. ENDPOINT,
  63. expect.objectContaining({
  64. data: {slug: 'new-slug'},
  65. })
  66. );
  67. expect(browserHistory.replace).toHaveBeenCalledWith('/settings/new-slug/');
  68. });
  69. });
  70. it('changes org slug and redirects to new customer-domain', async function () {
  71. const org = TestStubs.Organization({features: ['customer-domains']});
  72. const updateMock = MockApiClient.addMockResponse({
  73. url: `/organizations/${organization.slug}/`,
  74. method: 'PUT',
  75. body: {...org, slug: 'acme', links: {organizationUrl: 'https://acme.sentry.io'}},
  76. });
  77. render(<OrganizationGeneralSettings {...defaultProps} organization={org} />);
  78. const input = screen.getByRole('textbox', {name: /slug/i});
  79. userEvent.clear(input);
  80. userEvent.type(input, 'acme');
  81. userEvent.click(screen.getByLabelText('Save'));
  82. await waitFor(() => {
  83. expect(updateMock).toHaveBeenCalledWith(
  84. '/organizations/org-slug/',
  85. expect.objectContaining({
  86. data: {
  87. slug: 'acme',
  88. },
  89. })
  90. );
  91. expect(window.location.replace).toHaveBeenCalledWith(
  92. 'https://acme.sentry.io/settings/organization/'
  93. );
  94. });
  95. });
  96. it('disables the entire form if user does not have write access', function () {
  97. render(
  98. <OrganizationGeneralSettings
  99. {...defaultProps}
  100. organization={TestStubs.Organization({access: ['org:read']})}
  101. />
  102. );
  103. const formElements = [
  104. ...screen.getAllByRole('textbox'),
  105. ...screen.getAllByRole('button'),
  106. ...screen.getAllByRole('checkbox'),
  107. ];
  108. for (const formElement of formElements) {
  109. expect(formElement).toBeDisabled();
  110. }
  111. expect(
  112. screen.getByText(
  113. 'These settings can only be edited by users with the organization owner or manager role.'
  114. )
  115. ).toBeInTheDocument();
  116. });
  117. it('does not have remove organization button without org:admin permission', function () {
  118. render(
  119. <OrganizationGeneralSettings
  120. {...defaultProps}
  121. organization={TestStubs.Organization({
  122. access: ['org:write'],
  123. })}
  124. />
  125. );
  126. expect(
  127. screen.queryByRole('button', {name: /remove organization/i})
  128. ).not.toBeInTheDocument();
  129. });
  130. it('can remove organization when org admin', async function () {
  131. act(() => ProjectsStore.loadInitialData([TestStubs.Project({slug: 'project'})]));
  132. render(
  133. <OrganizationGeneralSettings
  134. {...defaultProps}
  135. organization={TestStubs.Organization({access: ['org:admin']})}
  136. />
  137. );
  138. renderGlobalModal();
  139. const mock = MockApiClient.addMockResponse({
  140. url: ENDPOINT,
  141. method: 'DELETE',
  142. });
  143. userEvent.click(screen.getByRole('button', {name: /remove organization/i}));
  144. const modal = screen.getByRole('dialog');
  145. expect(
  146. within(modal).getByText('This will also remove the following associated projects:')
  147. ).toBeInTheDocument();
  148. expect(within(modal).getByText('project')).toBeInTheDocument();
  149. userEvent.click(within(modal).getByRole('button', {name: /remove organization/i}));
  150. await waitFor(() => {
  151. expect(mock).toHaveBeenCalledWith(
  152. ENDPOINT,
  153. expect.objectContaining({
  154. method: 'DELETE',
  155. })
  156. );
  157. });
  158. });
  159. });