csp.spec.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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. await userEvent.click(
  57. await screen.findByRole('checkbox', {name: 'Use default ignored sources'})
  58. );
  59. expect(mock).toHaveBeenCalledWith(
  60. projectUrl,
  61. expect.objectContaining({
  62. method: 'PUT',
  63. data: {
  64. options: {
  65. 'sentry:csp_ignored_sources_defaults': true,
  66. },
  67. },
  68. })
  69. );
  70. });
  71. it('can set additional ignored sources', async function () {
  72. render(<ProjectCspReports />, {
  73. organization,
  74. });
  75. const mock = MockApiClient.addMockResponse({
  76. url: projectUrl,
  77. method: 'PUT',
  78. });
  79. expect(mock).not.toHaveBeenCalled();
  80. await userEvent.type(
  81. await screen.findByRole('textbox', {name: 'Additional ignored sources'}),
  82. 'test\ntest2'
  83. );
  84. // Focus on other element, trigerring onBlur
  85. await userEvent.tab();
  86. expect(mock).toHaveBeenCalledWith(
  87. projectUrl,
  88. expect.objectContaining({
  89. method: 'PUT',
  90. data: {
  91. // 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
  92. options: {
  93. 'sentry:csp_ignored_sources': `test\ntest2`,
  94. },
  95. },
  96. })
  97. );
  98. });
  99. });