add.spec.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  2. import {
  3. makeClosableHeader,
  4. makeCloseButton,
  5. ModalBody,
  6. ModalFooter,
  7. } from 'sentry/components/globalModal/components';
  8. import {convertRelayPiiConfig} from 'sentry/views/settings/components/dataScrubbing/convertRelayPiiConfig';
  9. import Add from 'sentry/views/settings/components/dataScrubbing/modals/add';
  10. import {MethodType, RuleType} from 'sentry/views/settings/components/dataScrubbing/types';
  11. import {
  12. getMethodLabel,
  13. getRuleLabel,
  14. } from 'sentry/views/settings/components/dataScrubbing/utils';
  15. const relayPiiConfig = TestStubs.DataScrubbingRelayPiiConfig();
  16. const stringRelayPiiConfig = JSON.stringify(relayPiiConfig);
  17. const organizationSlug = 'sentry';
  18. const rules = convertRelayPiiConfig(stringRelayPiiConfig);
  19. const successfullySaved = jest.fn();
  20. const projectId = 'foo';
  21. const endpoint = `/projects/${organizationSlug}/${projectId}/`;
  22. const api = new MockApiClient();
  23. describe('Add Modal', function () {
  24. it('open Add Rule Modal', async function () {
  25. const handleCloseModal = jest.fn();
  26. render(
  27. <Add
  28. Header={makeClosableHeader(handleCloseModal)}
  29. Body={ModalBody}
  30. Footer={ModalFooter}
  31. closeModal={handleCloseModal}
  32. CloseButton={makeCloseButton(handleCloseModal)}
  33. projectId={projectId}
  34. savedRules={rules}
  35. api={api}
  36. endpoint={endpoint}
  37. orgSlug={organizationSlug}
  38. onSubmitSuccess={successfullySaved}
  39. />
  40. );
  41. expect(
  42. screen.getByRole('heading', {name: 'Add an advanced data scrubbing rule'})
  43. ).toBeInTheDocument();
  44. // Method Field
  45. expect(screen.getByText('Method')).toBeInTheDocument();
  46. await userEvent.hover(screen.getAllByTestId('more-information')[0]);
  47. expect(await screen.findByText('What to do')).toBeInTheDocument();
  48. await userEvent.click(screen.getByText(getMethodLabel(MethodType.MASK).label));
  49. Object.values(MethodType).forEach(method => {
  50. if (method === MethodType.MASK) {
  51. return;
  52. }
  53. expect(screen.getByText(getMethodLabel(method).label)).toBeInTheDocument();
  54. });
  55. // Type Field
  56. expect(screen.getByText('Data Type')).toBeInTheDocument();
  57. await userEvent.hover(screen.getAllByTestId('more-information')[1]);
  58. expect(
  59. await screen.findByText(
  60. 'What to look for. Use an existing pattern or define your own using regular expressions.'
  61. )
  62. ).toBeInTheDocument();
  63. await userEvent.click(screen.getByText(getRuleLabel(RuleType.CREDITCARD)));
  64. Object.values(RuleType).forEach(rule => {
  65. if (rule === RuleType.CREDITCARD) {
  66. return;
  67. }
  68. expect(screen.getByText(getRuleLabel(rule))).toBeInTheDocument();
  69. });
  70. // Event ID
  71. expect(
  72. screen.getByRole('button', {name: 'Use event ID for auto-completion'})
  73. ).toBeInTheDocument();
  74. // Source Field
  75. screen.getByRole('textbox', {name: 'Source'});
  76. await userEvent.hover(screen.getAllByTestId('more-information')[2]);
  77. expect(
  78. await screen.findByText(
  79. 'Where to look. In the simplest case this can be an attribute name.'
  80. )
  81. ).toBeInTheDocument();
  82. // Close Modal
  83. await userEvent.click(screen.getByRole('button', {name: 'Cancel'}));
  84. expect(handleCloseModal).toHaveBeenCalled();
  85. });
  86. it('Display placeholder field', async function () {
  87. render(
  88. <Add
  89. Header={makeClosableHeader(jest.fn())}
  90. Body={ModalBody}
  91. Footer={ModalFooter}
  92. closeModal={jest.fn()}
  93. CloseButton={makeCloseButton(jest.fn())}
  94. projectId={projectId}
  95. savedRules={rules}
  96. api={api}
  97. endpoint={endpoint}
  98. orgSlug={organizationSlug}
  99. onSubmitSuccess={successfullySaved}
  100. />
  101. );
  102. expect(screen.queryByText('Custom Placeholder (Optional)')).not.toBeInTheDocument();
  103. await userEvent.click(screen.getByText(getMethodLabel(MethodType.MASK).label));
  104. await userEvent.keyboard('{arrowdown}{arrowdown}{enter}');
  105. expect(screen.getByText('Custom Placeholder (Optional)')).toBeInTheDocument();
  106. expect(screen.getByPlaceholderText('[Filtered]')).toBeInTheDocument();
  107. await userEvent.hover(screen.getAllByTestId('more-information')[1]);
  108. expect(
  109. await screen.findByText('It will replace the default placeholder [Filtered]')
  110. ).toBeInTheDocument();
  111. });
  112. it('Display regex field', async function () {
  113. render(
  114. <Add
  115. Header={makeClosableHeader(jest.fn())}
  116. Body={ModalBody}
  117. Footer={ModalFooter}
  118. closeModal={jest.fn()}
  119. CloseButton={makeCloseButton(jest.fn())}
  120. projectId={projectId}
  121. savedRules={rules}
  122. api={api}
  123. endpoint={endpoint}
  124. orgSlug={organizationSlug}
  125. onSubmitSuccess={successfullySaved}
  126. />
  127. );
  128. expect(screen.queryByText('Regex matches')).not.toBeInTheDocument();
  129. await userEvent.click(screen.getByText(getRuleLabel(RuleType.CREDITCARD)));
  130. await userEvent.keyboard(
  131. '{arrowdown}{arrowdown}{arrowdown}{arrowdown}{arrowdown}{arrowdown}{enter}'
  132. );
  133. expect(screen.getAllByText('Regex matches')).toHaveLength(2);
  134. expect(screen.getByPlaceholderText('[a-zA-Z0-9]+')).toBeInTheDocument();
  135. await userEvent.hover(screen.getAllByTestId('more-information')[2]);
  136. expect(
  137. await screen.findByText('Custom regular expression (see documentation)')
  138. ).toBeInTheDocument();
  139. });
  140. it('Display Event Id', async function () {
  141. const eventId = '12345678901234567890123456789012';
  142. MockApiClient.addMockResponse({
  143. url: `/organizations/${organizationSlug}/data-scrubbing-selector-suggestions/`,
  144. body: {
  145. suggestions: [
  146. {type: 'value', examples: ['34359738368'], value: "extra.'system.cpu.memory'"},
  147. {type: 'value', value: '$frame.abs_path'},
  148. ],
  149. },
  150. });
  151. render(
  152. <Add
  153. Header={makeClosableHeader(jest.fn())}
  154. Body={ModalBody}
  155. Footer={ModalFooter}
  156. closeModal={jest.fn()}
  157. CloseButton={makeCloseButton(jest.fn())}
  158. projectId={projectId}
  159. savedRules={rules}
  160. api={api}
  161. endpoint={endpoint}
  162. orgSlug={organizationSlug}
  163. onSubmitSuccess={successfullySaved}
  164. />
  165. );
  166. await userEvent.click(
  167. screen.getByRole('button', {name: 'Use event ID for auto-completion'})
  168. );
  169. await userEvent.click(screen.getByRole('textbox', {name: 'Source'}));
  170. expect(screen.getAllByRole('listitem')).toHaveLength(18);
  171. expect(screen.getByText('Event ID (Optional)')).toBeInTheDocument();
  172. await userEvent.type(
  173. screen.getByPlaceholderText('XXXXXXXXXXXXXX'),
  174. `${eventId}{enter}`
  175. );
  176. expect(await screen.findByTestId('icon-check-mark')).toBeInTheDocument();
  177. await userEvent.click(screen.getByRole('textbox', {name: 'Source'}));
  178. expect(screen.getAllByRole('listitem')).toHaveLength(3);
  179. });
  180. });