index.spec.tsx 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. import React from 'react';
  2. import {InjectedRouter} from 'react-router';
  3. import {Location} from 'history';
  4. import {initializeOrg} from 'sentry-test/initializeOrg';
  5. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  6. import {textWithMarkupMatcher} from 'sentry-test/utils';
  7. import GlobalModal from 'sentry/components/globalModal';
  8. import {Organization} from 'sentry/types';
  9. import {OrganizationContext} from 'sentry/views/organizationContext';
  10. import {RouteContext} from 'sentry/views/routeContext';
  11. import {DataScrubbing} from 'sentry/views/settings/components/dataScrubbing';
  12. const relayPiiConfig = JSON.stringify(TestStubs.DataScrubbingRelayPiiConfig());
  13. function ComponentProviders({
  14. router,
  15. location,
  16. organization,
  17. children,
  18. }: {
  19. children: React.ReactNode;
  20. location: Location;
  21. organization: Organization;
  22. router: InjectedRouter;
  23. }) {
  24. return (
  25. <OrganizationContext.Provider value={organization}>
  26. <RouteContext.Provider
  27. value={{
  28. router,
  29. location,
  30. params: {},
  31. routes: [],
  32. }}
  33. >
  34. {children}
  35. </RouteContext.Provider>
  36. </OrganizationContext.Provider>
  37. );
  38. }
  39. describe('Data Scrubbing', function () {
  40. describe('Organization level', function () {
  41. const {organization, router} = initializeOrg();
  42. const additionalContext = 'These rules can be configured for each project.';
  43. const endpoint = `organization/${organization.slug}/`;
  44. it('default render', function () {
  45. render(
  46. <ComponentProviders
  47. location={router.location}
  48. router={router}
  49. organization={organization}
  50. >
  51. <DataScrubbing
  52. additionalContext={additionalContext}
  53. endpoint={endpoint}
  54. relayPiiConfig={relayPiiConfig}
  55. organization={organization}
  56. onSubmitSuccess={jest.fn()}
  57. />
  58. </ComponentProviders>
  59. );
  60. // Header
  61. expect(screen.getByText('Advanced Data Scrubbing')).toBeInTheDocument();
  62. // Alert
  63. expect(
  64. screen.getByText(
  65. textWithMarkupMatcher(
  66. `${additionalContext} The new rules will only apply to upcoming events. For more details, see full documentation on data scrubbing.`
  67. )
  68. )
  69. ).toBeInTheDocument();
  70. expect(
  71. screen.getByRole('link', {name: 'full documentation on data scrubbing'})
  72. ).toHaveAttribute(
  73. 'href',
  74. `https://docs.sentry.io/product/data-management-settings/scrubbing/advanced-datascrubbing/`
  75. );
  76. // Body
  77. expect(screen.getAllByRole('button', {name: 'Edit Rule'})).toHaveLength(3);
  78. // Actions
  79. expect(screen.getByRole('button', {name: 'Read Docs'})).toHaveAttribute(
  80. 'href',
  81. `https://docs.sentry.io/product/data-management-settings/scrubbing/advanced-datascrubbing/`
  82. );
  83. expect(screen.getByRole('button', {name: 'Add Rule'})).toBeEnabled();
  84. });
  85. it('render empty state', function () {
  86. render(
  87. <ComponentProviders
  88. location={router.location}
  89. router={router}
  90. organization={organization}
  91. >
  92. <DataScrubbing
  93. endpoint={endpoint}
  94. relayPiiConfig={undefined}
  95. organization={organization}
  96. onSubmitSuccess={jest.fn()}
  97. />
  98. </ComponentProviders>
  99. );
  100. expect(screen.getByText('You have no data scrubbing rules')).toBeInTheDocument();
  101. });
  102. it('render disabled actions', function () {
  103. render(
  104. <ComponentProviders
  105. location={router.location}
  106. router={router}
  107. organization={organization}
  108. >
  109. <DataScrubbing
  110. additionalContext={additionalContext}
  111. endpoint={endpoint}
  112. relayPiiConfig={relayPiiConfig}
  113. organization={organization}
  114. onSubmitSuccess={jest.fn()}
  115. disabled
  116. />
  117. </ComponentProviders>
  118. );
  119. // Read Docs is the only enabled action
  120. expect(screen.getByRole('button', {name: 'Read Docs'})).toBeEnabled();
  121. expect(screen.getByRole('button', {name: 'Add Rule'})).toBeDisabled();
  122. for (const index in JSON.parse(relayPiiConfig).rules) {
  123. expect(screen.getAllByRole('button', {name: 'Edit Rule'})[index]).toBeDisabled();
  124. expect(
  125. screen.getAllByRole('button', {name: 'Delete Rule'})[index]
  126. ).toBeDisabled();
  127. }
  128. });
  129. });
  130. describe('Project level', function () {
  131. it('default render', function () {
  132. const {organization, router, project} = initializeOrg();
  133. render(
  134. <ComponentProviders
  135. location={router.location}
  136. router={router}
  137. organization={organization}
  138. >
  139. <DataScrubbing
  140. endpoint={`/projects/${organization.slug}/foo/`}
  141. relayPiiConfig={relayPiiConfig}
  142. organization={organization}
  143. onSubmitSuccess={jest.fn()}
  144. project={project}
  145. />
  146. </ComponentProviders>
  147. );
  148. // Header
  149. expect(
  150. screen.getByText('There are no data scrubbing rules at the organization level')
  151. ).toBeInTheDocument();
  152. });
  153. it('OrganizationRules has content', function () {
  154. const {organization, router, project} = initializeOrg({
  155. ...initializeOrg(),
  156. organization: {
  157. ...initializeOrg().organization,
  158. relayPiiConfig,
  159. },
  160. });
  161. render(
  162. <ComponentProviders
  163. location={router.location}
  164. router={router}
  165. organization={organization}
  166. >
  167. <DataScrubbing
  168. endpoint={`/projects/${organization.slug}/foo/`}
  169. relayPiiConfig={relayPiiConfig}
  170. organization={organization}
  171. onSubmitSuccess={jest.fn()}
  172. project={project}
  173. />
  174. </ComponentProviders>
  175. );
  176. // Organization Rules
  177. expect(screen.getByText('Organization Rules')).toBeInTheDocument();
  178. });
  179. it('Delete rule successfully', async function () {
  180. const {organization, router, project} = initializeOrg();
  181. render(
  182. <ComponentProviders
  183. location={router.location}
  184. router={router}
  185. organization={organization}
  186. >
  187. <GlobalModal />
  188. <DataScrubbing
  189. endpoint={`/projects/${organization.slug}/foo/`}
  190. project={project}
  191. relayPiiConfig={relayPiiConfig}
  192. disabled={false}
  193. organization={organization}
  194. onSubmitSuccess={jest.fn()}
  195. />
  196. </ComponentProviders>
  197. );
  198. userEvent.click(screen.getAllByLabelText('Delete Rule')[0]);
  199. expect(
  200. await screen.findByText('Are you sure you wish to delete this rule?')
  201. ).toBeInTheDocument();
  202. });
  203. it('Open Add Rule Modal', async function () {
  204. const {organization, router, project} = initializeOrg();
  205. render(
  206. <ComponentProviders
  207. location={router.location}
  208. router={router}
  209. organization={organization}
  210. >
  211. <GlobalModal />
  212. <DataScrubbing
  213. endpoint={`/projects/${organization.slug}/foo/`}
  214. project={project}
  215. relayPiiConfig={relayPiiConfig}
  216. disabled={false}
  217. organization={organization}
  218. onSubmitSuccess={jest.fn()}
  219. />
  220. </ComponentProviders>
  221. );
  222. userEvent.click(screen.getByRole('button', {name: 'Add Rule'}));
  223. expect(
  224. await screen.findByText('Add an advanced data scrubbing rule')
  225. ).toBeInTheDocument();
  226. });
  227. it('Open Edit Rule Modal', function () {
  228. const {organization, router, project} = initializeOrg();
  229. render(
  230. <ComponentProviders
  231. location={router.location}
  232. router={router}
  233. organization={organization}
  234. >
  235. <GlobalModal />
  236. <DataScrubbing
  237. endpoint={`/projects/${organization.slug}/foo/`}
  238. project={project}
  239. relayPiiConfig={relayPiiConfig}
  240. disabled={false}
  241. organization={organization}
  242. onSubmitSuccess={jest.fn()}
  243. />
  244. </ComponentProviders>
  245. );
  246. userEvent.click(screen.getAllByRole('button', {name: 'Edit Rule'})[0]);
  247. // Verify the router to open the modal was called
  248. expect(router.push).toHaveBeenCalledWith(
  249. expect.objectContaining({
  250. pathname: `/settings/${organization.slug}/projects/${project.slug}/security-and-privacy/advanced-data-scrubbing/0/`,
  251. })
  252. );
  253. });
  254. });
  255. });