csp.spec.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import {initializeOrg} from 'sentry-test/initializeOrg';
  2. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  3. import ProjectCspReports from 'sentry/views/settings/projectSecurityHeaders/csp';
  4. describe('ProjectCspReports', function () {
  5. const {project, organization} = initializeOrg();
  6. const projectUrl = `/projects/${organization.slug}/${project.slug}/`;
  7. beforeEach(function () {
  8. MockApiClient.clearMockResponses();
  9. MockApiClient.addMockResponse({
  10. url: `/projects/${organization.slug}/${project.slug}/keys/`,
  11. method: 'GET',
  12. body: [],
  13. });
  14. MockApiClient.addMockResponse({
  15. url: projectUrl,
  16. method: 'GET',
  17. body: {
  18. options: {},
  19. },
  20. });
  21. });
  22. it('renders', async function () {
  23. render(<ProjectCspReports />, {
  24. organization,
  25. });
  26. // Renders the loading indication initially
  27. expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
  28. // Heading
  29. expect(
  30. await screen.findByText('Content Security Policy', {selector: 'h4'})
  31. ).toBeInTheDocument();
  32. });
  33. it('renders loading error', async function () {
  34. MockApiClient.addMockResponse({
  35. url: projectUrl,
  36. method: 'GET',
  37. statusCode: 400,
  38. body: {},
  39. });
  40. render(<ProjectCspReports />, {
  41. organization,
  42. });
  43. expect(
  44. await screen.findByText('There was an error loading data.')
  45. ).toBeInTheDocument();
  46. });
  47. it('can enable default ignored sources', async function () {
  48. render(<ProjectCspReports />, {
  49. organization,
  50. });
  51. const mock = MockApiClient.addMockResponse({
  52. url: projectUrl,
  53. method: 'PUT',
  54. });
  55. expect(mock).not.toHaveBeenCalled();
  56. // Click Regenerate Token
  57. await userEvent.click(
  58. await screen.findByRole('checkbox', {name: 'Use default ignored sources'})
  59. );
  60. expect(mock).toHaveBeenCalledWith(
  61. projectUrl,
  62. expect.objectContaining({
  63. method: 'PUT',
  64. data: {
  65. options: {
  66. 'sentry:csp_ignored_sources_defaults': true,
  67. },
  68. },
  69. })
  70. );
  71. });
  72. it('can set additional ignored sources', async function () {
  73. render(<ProjectCspReports />, {
  74. organization,
  75. });
  76. const mock = MockApiClient.addMockResponse({
  77. url: projectUrl,
  78. method: 'PUT',
  79. });
  80. expect(mock).not.toHaveBeenCalled();
  81. await userEvent.type(
  82. await screen.findByRole('textbox', {name: 'Additional ignored sources'}),
  83. 'test\ntest2'
  84. );
  85. // Focus on other element, trigerring onBlur
  86. await userEvent.tab();
  87. expect(mock).toHaveBeenCalledWith(
  88. projectUrl,
  89. expect.objectContaining({
  90. method: 'PUT',
  91. data: {
  92. // XXX: Org details endpoints accept these multiline inputs as a list, where as it looks like project details accepts it as a string with newlines
  93. options: {
  94. 'sentry:csp_ignored_sources': `test\ntest2`,
  95. },
  96. },
  97. })
  98. );
  99. });
  100. });